Expert Opinion | 삼일피더블유씨솔루션

내부회계관리제도와 AI의 활용 (부정위험관리)

작성자: 김형남 회계사 | 한서회계법인 파트너 | Mar 27, 2026 7:05:21 AM
김형남 회계사_한서회계법인 파트너
 
김형남 회계사는 한서회계법인의 파트너이며 한국공인회계사이자 공인부정조사사(CFE)이다. 연세대학교 경제학 석사이며 홍익대학교에서 경제학을 전공하였다. Deloitte 안진회계법인에서 기업구조조정 프로젝트를 경험한 후, 삼정KPMG의 금융사업본부에서 내부회계관리제도 구축 및 평가, 은행내부통제 진단, M&A, 국제회계기준 도입 등 다양한 금융회사에 대한 컨설팅과 회계감사를 담당하였다. 특히, 국내에 내부회계관리제도 도입당시 내부감사 및 내부통제 전문컨설팅 그룹인 Protiviti에서 전문적인 지식을 습득하고 다양한 프로젝트 경험을 쌓았다. 현재는 다양한 금융회사, 부동산자산운용회사, 기업체, 정부기관 등에서 강연과 공인회계사 전문 컨설팅을 제공하고 있다. 
 

광장시장의 바가지 논란은 잊혀질만 하면 다시 반복되어 도마위에 올라오는 단골 메뉴이다. 한두명의 욕심많은 상인의 부정행위는 상인의 개인적 일탈로 끝나지 않는다. 고객은 대표 전통시장인 광장시장 전체에 대한 신뢰성을 무너뜨리게 되고, 부정적 이미지와 낙인효과(stigma effect) 단기에 끝나지 않는 것이 특징이다.

이렇게 일부의 부정행위(혹은 bad apple, 썩은 사과) 집단이나 조직 전체의 신뢰성을 떨어뜨리고 전이되는 현상을 Reputational spillover(평판 전이)라고 하는데 이러한 현상은 많은 시사점을 갖고 있다.

회사 혹은 조직에서도 만약 분식회계와 같은 재무제표 왜곡표시나 특정 개인의 부정행위가 발견된다면 이는 일부에서 끝나는 것이 아니라, 오랫동안 쌓아온 조직 전체의 평판과 신뢰성을 한꺼번에 무너뜨릴 수도 있다는 사실이다.

 

< 표: 광장시장의 바가지에 대한 Reputational spillover 효과 >


따라서, 이러한 위험을 막기위한 내부통제 절차가 필요할 밖에 없다. 이번 연재에서는 AI 활용하여 부정위험을 막기위한 방법을 알아본다.

 

1. 부정위험은 어떻게 발생할까?

어떠한 내부통제도 위험을 완전하게 막을 없다. 이는 내부통제에는 고유 한계가 존재한다는 것을 의미하는데 이는 부정위험도 마찬가지이다.

이는 화재에 있어서 소화기와 스프링클러를 준비한다고 하더라도 모든 화재사건을 막을 없는 것과 마찬가지이다. 하지만, 소화기와 스프링클러가 있다면 화재사건의 규모를 대폭 낮출 있다.

부정위험과 관련하여서는 부정 삼각형 이론(fraud triangle theory) 소화기와 스프링쿨러의 역할을 하게 된다. 부정위험은 압력(pressure), 기회(opportunity), 합리화(rationalization) 동시에 존재하는 경우 발생할 가능성이 더욱 높아지므로 각각의 항목을 평가하여 동시에 발생하지 않도록 관리하는 것이다.

< 표: 부정 삼각형 이론 >

부정 삼각형 이론은 범죄학자에 의해 연구되고 발전되어온 이론이다. 이는 본질적으로 기회, 압력 합리화(정당화) 가지 요소가 있으면 부정이 발생한다고 본다. 이는 화재를 유발하는 연료, 스파크 산소와 비유할 있는데, 3가지가 함께 작용하면 필연적으로 화재가 발생하는 것과 같은 이치라고 있다.

그러므로 내부회계관리제도에서는 압력, 기회, 합리화에 대한 내부통제 절차를 마련하여 적용하여야 한다. 압력(pressure) 고충처리제도와 같은 제도를 통해 고위험 직군의 인력에 대한 관리를 생각해 있고, 합리화(rationalization) 강의, 교육, 홍보활동 등으로차용, 자격의식, 상대적 금액, 모두 불리는 도덕의식을 낮추는 행위에 대해 경종을 울릴 있다. 이렇게 압력이나 합리화와 관련하여서는 AI환각(hallucination)”이라는 부작용 없이 사용할 있는 여지가 별로 없다. 따라서, 기회(opportunity) 대한 내부통제 활동에 AI 적극적으로 활용하여 있다.

ACFE Fraud Manual에서는 수십개의 부정위험 유형을 다루고 있는데 이중 많은 회사에 공통적이면서 대표적인 3가지의 부정위험에 대한 내부통제 절차를 AI 활용하여 소개하고자 한다.

  • 유령직원 (ghost employee)
  • 비용의 이중지급 (expense reimbursement scheme)
  • 부당한 지급처 (shell company)

2. 유령직원의 등장 (ghost employee)

급여를 통해 자금을 빼돌리는 기법은 아주 오래된 고전적인 기법이다. 그럼에도 불구하고 AI시대에도 지속적으로 발생하는 이유는 무엇일까? 우선 부정을 발생시키기 매우 쉬운 환경이라는 점이고, 또한 급여지급 프로세스가 거의 자동화되어 사람에 의한 모니터링이 약화된 측면도 부정할 없을 것이다.

급여의 가장 대표적인 부정유형은 유령직원(ghost employee)라고 있는데, 이는 실제 존재하거나 근무하지 않는 인력(예를들어 퇴사한 인력) 급여대장에 포함시키고, 정상적인 급여지급 처럼 자금을 횡령하는 기법이다. 유령직원은 세부적으로 보자면 기법이 더욱 복잡해 있지만 우선 인사카드와 급여대장을 대조함으로써 실제 존재하지 않는 인원에 대해 급여가 지급되었는지를 파악할 있다.

만약 인사카드와 급여대장이 준비되었다면 두개의 화일을 업로드하고 ChatGPT Gemini 이용하여 다음과 같은 프롬프트를 입력한다.


다음은 ChatGPT와 Gemini의 Z-score에 대한 답변 사례이다.

ChatGPT

Gemini

다음 1명이 인사카드에는 존재하지 않으나 7월 급여대장에만 존재하여 급여가 지급된 인원입니다.

🔍 인사카드 미등재 + 급여대장 포함 인원

(*이름 및 급여는 가상 데이터 입니다)

추가분석(중복 여부, 6월 대비 비교 등)이 필요하면 알려주시면 바로 처리해드릴게요!

인사카드에는 없지만 7월 급여대장에 포함되어 급여가 지급된 인원은 서하원입니다.

import pandas as pd

# 파일 불러오기

payroll = pd.read_excel('/mnt/data/급여대장_7월.xlsx')

hr = pd.read_csv('/mnt/data/인사카드.csv')

# 인사카드에 존재하지 않는 인원 추출

missing = payroll[~payroll['이름'].isin(hr['이름'])]

print(missing)

iimport pandas as pd

# 파일 불러오기

file_path_insa = '인사카드.csv'

file_path_salary = '급여대장_7월.xlsx - Sheet1.csv'

df_insa = pd.read_csv(file_path_insa)

df_salary = pd.read_csv(file_path_salary)

# 인사카드에 있는 이름 목록 추출 (중복 제거)

insa_names = set(df_insa['이름'].dropna().unique())

# 급여대장에는 있지만 인사카드 이름 목록에 없는 인원 필터링

missing_in_insa = df_salary[~df_salary['이름'].isin(insa_names)]

# 결과 출력

print("인사카드에 없으나 급여대장에 포함된 인원:")

print(missing_in_insa[['이름']])

이러한 유령직원에 대한 부정위험 검토는 매우 중요하다. 심화된 기법으로는 실재 출입기록 데이터르 대조하여 근무하지 않는 인력을 검토할 수도 있고, 임률이 변동하거나 특정 정도 이상 변화한 급여에 대해서도 검토해 봄으로써 급여를 통한 부정위험을 검증해 있으므로 추천한다.

 

3. 영수증 하나로 두번 지급받기 (비용의 이중지급, expense reimbursement scheme)

이렇게 비용들을 많이 쓰는거야아니면영수증 하나로 두번 경비지급을 받은거 아니야라는 의구심은 경영진의 가장 보편적인 의심병중의 하나이다. 실제로 직원도 내부통제가 헐거워진 틈을 이용하여 실제로 두번 경비를 청구하고 지급받는 사례도 발생하곤 한다.

예전에 비해 경비지출에 대한 전산화 강화로 많이 줄어드는 추세이기는 하지만, 하나의 지출건 영수증으로 영업부서와 구매부서에 각각 경비청구를 올리기도 하고, 시점을 달리하여 3월에 청구하고 잊어버릴 때쯤 7월에 다시 청구하는 건이 많이 발견된다.

1년간의 비용지급 데이터가 확보되었다면 이중 여러 필드값이 일치하는 내용은 한번의 지출로 2번이상 지급되었을 가능성이 있으므로 다음과 같이 프롬프트를 입력한다.

다음은 ChatGPT와 Gemini의 Z-score에 대한 답변 사례이다.

ChatGPT

Gemini

완료했습니다!

거래처코드 + 적요 + 차변

3개 칼럼이 모두 동일한 중복 거래를 전부 추출하여 정렬한 뒤, 아래 파일로 저장해두었습니다.

👉 중복_추출결과.xlsx 다운로드

필요하시면 특정 월만 필터링

추가 조건(예: 대변=0원) Pivot 분석

그래프 시각화 등도 바로 만들어드릴게요!

요청하신 거래처코드, 적요, 차변(차 변) 3가지 항목이 모두 일치하는 중복 내역을 추출하였습니다.

총 588건의 중복 내역이 발견되었으며, 해당 내역을 확인하실 수 있도록 CSV 파일로 저장했습니다.

전체 리스트는 아래 파일을 다운로드하여 확인해 주세요. duplicate_records.csv

import pandas as pd

# 1. 엑셀 파일 불러오기

file_path = "미지급금반제.xlsx" # 파일명 입력

df = pd.read_excel(file_path)

# 2. 칼럼명 공백 제거(엑셀에서 '차 변'처럼 띄어쓰기 문제 방지)

df = df.rename(columns=lambda x: x.strip().replace(" ", ""))

# 3. 중복 확인 기준 칼럼 설정

key_cols = ['거래처코드', '적요', '차변']

# 4. 기준 칼럼 3개가 모두 동일한 건 추출

duplicates = df[df.duplicated(subset=key_cols, keep=False)].sort_values(key_cols)

# 5. 결과 저장

output_path = "중복_추출결과.xlsx"

duplicates.to_excel(output_path, index=False)

print("중복 건 추출 완료:", output_path)

import pandas as pd

file_path = '미지급금반제.xlsx - 미지급금 반제 원장 검토.csv'

df = pd.read_csv(file_path)

print(df.head())

print(df.info())

# Identify duplicates based on the specified columns

duplicate_mask = df.duplicated(subset=['거래처코드', '적요', '차변'], keep=False)

duplicates_df = df[duplicate_mask]

# Sort the duplicates to group identical records together for easier inspection

duplicates_df = duplicates_df.sort_values(by=['거래처코드', '적요', '차변'])

# Save the result to a CSV file

output_file = 'duplicate_records.csv'

duplicates_df.to_csv(output_file, index=False, encoding='utf-8-sig') # using utf-8-sig for Korean characters

print(f"Number of duplicate records found: {len(duplicates_df)}")

print(duplicates_df.head())

 
4. 유령회사를 만들어서 지급을? (부당한 지급처, shell company)

 

현금 지출이 가장 많이 일어나는 활동은 뭐니뭐니 해도 구매 업무일 것이다. 만약 건수가 매우 많아서 구매 과정의 내부통제가 취약하다고 한다면 담당자는내가 회사를 하나 만들어서 우리회사에 세금계산서를 보내면 자동으로 돈을 수도 있겠다 생각을 수도 있을 것이다.

이런 과정은 생각에서만 그치는 것이 아니라 많은 회사에서 발생한 전형적인 구매과정에서의 부정행위이다. 이러한 가짜회사, 유령회사를 통상 shell company라고 하는데 임직원이 직접 만들거나 아니면 3자를 이용하여 여러 개의 회사를 만들고 유의한 금액 미만(혹은 수행중요성금액 미만) 세금계산서를 여러 발행하여 횡령하는 수법이 대표적이다.

그렇다고 한다면 내부회계관리제도에서는 다음의 내용을 이용하여 벤더에 대한 검토를 수행해 수도 있다.

내용

검토의 목적

당사 직원이 만든 회사

당사 직원이 유령회사를 만들어 당사에 세금계산서를 발행하고 이를 통해 횡령하는 수법을 검토

동일 벤더 검토

업체명은 여러 개로 상이하지만 동일한 사업자 주소로 등록된 벤더를 검토.

가짜 회사를 만든다고 하더라도 동일 사업자 주소(공유오피스 등)로 사업자등록증을 발급받는 경우가 많은 것에 착안하는 방식

동일 대표자 검색

당사직원이 아나더라도 제3자(혹은 가족 등) 한명의 명의를 이용하여 여러 개의 유령 회사를 만드는 패턴에 착안하여 검토

유효하지 않은 사업자 주소

일반적으로 가짜회사를 만들 때 유효하지 않은 사업자주소 혹은 사서함을 이용하는 경우가 많음

검토를 위한 대부분의 Key 정보는 매입세금계산서목록에 대표자, 주소, 업체명, 사업자등록번호 등이 나오기 때문에 데이터 확보에 어려움은 없으며, 데이터 분석은 별개의 모델링을 하지 않더라도 인공지능이 수행할 있는 부분이다.

이중 첫번째인당사 직원이 만든 회사 대해 ChatGPT Gemini 다음과 같은 프롬프트를 입력한다.

 

ChatGPT

Gemini

매입세금계산서(입력 VAT 리스트)에서 **공급자 대표자명(‘대표자명’ 컬럼)**과
인사카드의 **이름(‘이름’ 컬럼)**이 일치하는 건은 총 12건입니다.

아래 표는 그 12건을 주요 컬럼 위주로 정리한 것입니다.

기준 컬럼

    • 인사카드: 이름
    • 매입세금계산서: 대표자명
      두 컬럼을 공백 제거 후 완전 일치하는 건만 추출했습니다.

 

혹시 이 일치 내역을 별도 엑셀 파일로 저장해서 받고 싶으시면,
“엑셀로 저장해줘”라고 말씀해 주시면 다운로드할 수 있는 파일로 만들어 드리겠습니다.

요청하신 대로 input VAT list_2Q.xlsx 파일의 H열(대표자명)과 인사카드.csv 파일의 A열(이름)을 비교하여, 이름이 일치하는 모든 항목을 추출했습니다. 비교 시 각 이름의 공백은 모두 제거하고 진행하였습니다.

분석 결과는 다음과 같습니다.

    • 일치하는 이름: 총 2명 ('서가결', '정은우')
    • 추출된 항목 수: 총 12건 (정은우 10건, 서가결 2건)

추출된 상세 내역은 아래의 CSV 파일로 저장했습니다.

[결과 파일]

    • matched_vat_entries.csv: 일치하는 대표자명이 포함된 VAT 목록의 전체 행

결과를 확인해 보시기 바랍니다.

import pandas as pd

# 1. 파일 불러오기

df_hr = pd.read_csv("인사카드.csv", encoding="utf-8") # 인사카드

df_vat = pd.read_excel("input VAT list_2Q.xlsx") # 매입세금계산서

# 2. 비교 대상 컬럼 정리 (공백 제거)

df_hr["이름_clean"] = df_hr["이름"].str.strip()

df_vat["대표자명_clean"] = df_vat["대표자명"].str.strip()

# 3. 대표자명과 인사카드 이름이 일치하는 행 추출

matched = df_vat[df_vat["대표자명_clean"].isin(df_hr["이름_clean"])]

# 4. 결과 출력

print("일치하는 건수:", len(matched))

print(matched)

# 5. 필요한 경우 엑셀로 저장

matched.to_excel("대표자명_일치_추출결과.xlsx", index=False)

import pandas as pd

# 1. 파일 불러오기

# 실제 환경에서는 파일 경로가 다를 수 있습니다.

vat_list_df = pd.read_csv('input VAT list_2Q.xlsx - Sheet1.csv')

personnel_card_df = pd.read_csv('인사카드.csv')

# 2. 데이터 전처리 (공백 제거)

# 비교를 위해 '대표자명'과 '이름' 컬럼의 모든 공백을 제거합니다.

vat_list_df['대표자명_clean'] = vat_list_df['대표자명'].astype(str).str.replace(r'\s+', '', regex=True)

personnel_card_df['이름_clean'] = personnel_card_df['이름'].astype(str).str.replace(r'\s+', '', regex=True)

# 3. 일치하는 이름 찾기 (교집합)

common_names = set(vat_list_df['대표자명_clean']).intersection(set(personnel_card_df['이름_clean']))

# 4. 일치하는 항목 추출

# 대표자명이 교집합에 속하는 행만 필터링합니다.

matched_vat_list = vat_list_df[vat_list_df['대표자명_clean'].isin(common_names)].copy()

# (선택 사항) 인사카드에서도 일치하는 항목 확인

matched_personnel = personnel_card_df[personnel_card_df['이름_clean'].isin(common_names)].copy()

# 결과 출력

print(f"일치하는 이름 수: {len(common_names)}")

print(f"일치하는 이름 목록: {common_names}")

print("\n[추출된 VAT 목록 예시]")

print(matched_vat_list.head())

# 5. 결과 저장

# 전처리를 위해 만든 임시 컬럼('대표자명_clean')을 제외하고 저장합니다.

output_filename = 'matched_vat_entries.csv'

matched_vat_list.drop(columns=['대표자명_clean']).to_csv(output_filename, index=False)

print(f"\n결과가 '{output_filename}' 파일로 저장되었습니다.")

만약 동명이인이 있을 수도 있기 때문에 동일인이 검색되었다고 하더라도 추가적인 절차를 수행해야 한다. 법인등기부등본을 떼어 보면 대표자의 주민등록번호 앞자리(생년월일) 정보를 확인할 있으므로 당사 직원이 만든 회사인지 아니면 단순한 동명이인인지 확인가능하다.

지면 관계상 하나의 사례를 들었으나 동인 벤더 검토, 동일 대표자, 유효하지 않은 사업자 주소 등도 유사하게 활용해볼 있다.

결론: 부정이라고 해서 특별하지 않다

부정위험을 다루는 절차를 생각하면 뭔가 화려하거나 아주 정교한 기법이 사용될 같지만 실제로 부정을 다루는 기법은 상식선에서 이해가 가능한 기법이 많다. 부정위험을 검토하기 위한 기법의 정교함보다 중요한 것은 부정행위를 적발하는 기법에 의해 매년 이상징후가 AI 의해 검토된다는 사실을 직원과 함께 공유하는 것이다.

잡힌다는 생각이 든다면 누가 그런 행위를 하겠는가?

 

#내부회계관리제도 #AI #내부회계관리제도와AI #부정위험 #내부통제 #부정삼각형이론
 
Legal Disclaimer
해당 자료의 내용은 집필자의 개인적인 의견으로 삼일피더블유씨솔루션(주)의 공식적인 의견이 아님을 밝힙니다.
 
Copyright(C) 삼일피더블유씨솔루션㈜ All right reserved.
본 사이트에 게재된 자료들은 저작권법에 의하여 보호 받는 저작물로 그 저작권은 삼일피더블유씨솔루션(주)에 있으므로 무단 복제 및 배포를 금합니다.