SM20 records exactly which account read USR02, AGR_USERS, or RFCDES, from which IP, and when — but it never records why. A sanctioned vulnerability scanner and a post-exploitation enumeration script can leave an identical trail across identity, authorization, and system tables.
This prompt builds a full account inventory, flags every dual-use account (a service or RFC identity also used for interactive logon — a mandatory check, run on every account, no exceptions), and scores every table read against a privileged watchlist headed by USR02, AGR_*, and RFCDES. Where a read pattern matches the textbook reconnaissance signature, it says so plainly — and says just as plainly that SM20 alone can’t tell you if it’s your own scanner or someone else’s.
It’s free. No form, no login. Reduce your export first (see below), then copy the prompt and run it against your own data.
How this works
- Export the audit log. Run SM20 (or RSAU_READ_LOG on S/4HANA) for your date range, all clients, all users, all audit classes, and save it as CSV or tab-delimited text.
- Reduce the export. Run the free sm20_reduce.py script (or the Excel filter) to split a raw export into a volume summary and a security-signal detail file before pasting anything into an LLM.
- Run the privileged-access prompt. Copy the prompt below into your company-approved LLM — a commercial assistant or a model running on your own infrastructure — and attach the summary and signal files (or the raw export, if you have not reduced it yet).
- Read the account inventory and access register. Start with any account flagged DUAL-USE and any row in the reconnaissance-signature list — those are the ones that need a human decision, not just a read.
Reduce the export first
An SM20 export can run to tens of thousands of records fast. In our test export, two and a half days from a single system produced 36,362 records — roughly 1.8 million tokens at an approximate 50 tokens per row. Too large for most models, and unnecessary: 95% of that file was operational noise (a single background job re-authenticating was 73% on its own) and only 0.57% of records carried security signal. You would be paying to load 36,362 rows in order to read 209.
Option A — filter on the SM20 selection screen (no scripting)
| Setting | Value | Why |
|---|---|---|
| Audit classes | Untick RFC Function Call and Report Start | Highest-volume, lowest-value classes |
| Severity | Critical + Severe only | Drops the batch-logon flood |
| User | Exclude DDIC, SAPSYS, and your batch user | One batch user alone was 73% of our test file |
| Date range | 24–72 hours at a time | Not 30 days |
Dropping the machine-logon flood removes most of the file.
Filtering out the batch logons also removes the evidence for the single biggest finding in our test — "one job is consuming 73% of your audit log capacity." If you want that finding, use Option B.
Option B — two files (recommended)
Produce two files and attach both:
sm20_summary.csv— aggregate of the FULL export:Event | User | Client | Peer | ABAP Source | Count. One row per unique combination, so tens of thousands of records collapse to a few hundred rows. Preserves the volume picture. No timestamps.sm20_signal.csv— full-detail rows, filtered to security-relevant events only — typically a small fraction of the raw export.
AU2, AU4, AU5, AU6, AU7, AU8, AU9, AUA, AUB, AUD, AUE, AUF, AUI, AUJ,
AUL, AUM, AUN, AUY, BU1, BUJ, CUZ
+ AU3 rows where the transaction is on the privileged list
+ DU9 rows where the auth check FAILED
+ AU1 rows where logon type is A or H (interactive) — needed to spot dual-use accounts
Use the free reducer script below, or the Excel formula, to produce both files.
Excel filter for sm20_signal.csv
=OR(
ISNUMBER(MATCH([@Event],{"AU2","AU4","AU5","AU6","AU7","AU8","AU9","AUA","AUB","AUD","AUE","AUF","AUI","AUJ","AUL","AUM","AUN","AUY","BU1","BUJ","CUZ"},0)),
AND([@Event]="DU9", ISERROR(SEARCH("passed",[@[Audit Log Message]]))),
AND([@Event]="AU1", OR([@[Variable Data]]="A",[@[Variable Data]]="H")),
AND([@Event]="AU3", ISNUMBER(MATCH([@[Variable Data]],{"SU01","SU10","PFCG","SE38","SE37","SE80","SE16","SE16N","SM30","SM31","SM34","SM59","SM49","SM69","SCC4","SCC5","RZ10","RZ11","STMS","SM01","SM12","SM19","SM20","SA38","SE93","SE11","ST05"},0)))
)
Filter to TRUE, copy the visible rows out.
Free download — sm20_reduce.py
Run the reducer script to produce both files automatically, or use the Excel formula above.
Download sm20_reduce.py See the full script and how it works →
What you'll need
| Column | Source |
|---|---|
SAP System | SID |
AS Instance | Application server instance |
Date / Time | Event timestamp |
Cl. | Client (MANDT) |
Event | Audit message ID (AU1, AU2, AU3, AUD, BU1, CUZ, DU9, BUJ…) |
User | SAP user ID |
Terminal | Workstation name |
Peer | Source IP address |
TCode | Transaction code |
ABAP Source | Calling program |
Audit Log Message | Resolved message text |
Variable Data / Variable 2 / Variable 3 | Message parameters (tcode, reason code, logon type) |
Export from SM20 (or RSAU_READ_LOG on S/4HANA) for your date range, all clients, all users, all audit classes. Save as a CSV with the columns above.
The prompt
Copy this verbatim into your LLM of choice, then attach the CSV described above.
You are an SAP security analyst. You are given an SM20 / RSAU Security Audit Log
export. Analyse privileged users, service and machine accounts, and all direct
table access. Determine what was read, by whom, from where, and whether the
pattern matches the account's stated purpose.
Source columns:
SAP System, AS Instance, Date, Time, Cl., Event, User, Terminal, Peer, TCode,
ABAP Source, Audit Log Message, Variable Data, Variable 2, Variable 3
===========================================================================
STEP 0 - INPUT HANDLING
===========================================================================
If given only an aggregated summary (Count column, no Time column), you can still
build the account inventory and the table-access register, but you CANNOT detect
the reconnaissance BURST in STEP 4, which depends on timing. Say so explicitly
rather than guessing.
If given a raw unfiltered export, extract only AU1, AU3, AU6, AUY, CUZ and DU9
first, and state how many records you filtered down from.
===========================================================================
THE NULL-EVIDENCE RULE
===========================================================================
The absence of a logon record for an RFC or service account is NOT evidence that
it bypassed the audit trail. Successful RFC logons, trusted-RFC calls and reused
sessions may legitimately produce no AU1/AU6 record depending on which audit
classes are active. NEVER write "no logon event exists, therefore this connection
evaded auditing." If the absence is material, report it as an open question with
confidence "Requires Correlation" and name SM19 / RSAU_CONFIG and SM59 as checks.
===========================================================================
STEP 1 - BUILD THE ACCOUNT INVENTORY
===========================================================================
For every distinct User report: total events, distinct event IDs, distinct source
IPs, distinct terminals, LOGON TYPES USED, first and last activity, clients active in.
Logon types: A = Dialog, H = HTTP/Fiori -> HUMAN
B, E, F, G, S, V -> MACHINE
Classify each account:
STANDARD SAP ACCOUNT : DDIC, SAP*, SAPCPIC, EARLYWATCH, TMSADM
LIKELY MACHINE/SERVICE : only MACHINE logon types; or only RFC events; or a
constant, evenly-spaced event rate
LIKELY HUMAN : HUMAN logon types, bursty activity, transaction starts
DUAL-USE : BOTH machine-type activity (MACHINE logon type, or CUZ
RFC table access) AND a HUMAN logon type
===========================================================================
STEP 2 - DUAL-USE IS A FINDING. RUN THIS CHECK ON EVERY ACCOUNT.
===========================================================================
For each dual-use account, raise it explicitly. Rate HIGH.
Reasoning to state: a service or RFC account that is ALSO used for interactive
dialog logon destroys attribution - you can no longer tell whether an action was
taken by the interface or by a person using its credentials. Every action the
interface performs and every action the person performs land under the same user
ID in every log you own.
Recommend: set the user type to SYSTEM or SERVICE (USR02-USTYP = B or S) so dialog
logon becomes impossible, and rotate the password.
Do NOT skip this check because the account "looks like" a scanner, a monitoring
tool, or an admin's personal account. The check is mechanical: machine activity
plus a human logon type equals dual-use, regardless of what the account is called.
===========================================================================
STEP 3 - DIRECT TABLE ACCESS
===========================================================================
Extract every:
CUZ Generic table access BY RFC -> EXTERNAL (remote, no SAPGUI)
DU9 Generic table access call -> INTERNAL (SE16 / SM30 / report)
Parse the TABLE NAME and the ACTIVITY from each message.
Activity 02 = change Activity 03 = display
Score each table against this watchlist. Unlisted tables: score as Business Data,
unless read at activity 02, in which case treat as Configuration Change.
IDENTITY & CREDENTIALS (highest sensitivity):
USR02 (holds password hashes), USR21, USER_ADDR, ADRP, ADR6, USRACL
AUTHORIZATION & ROLES:
AGR_1251, AGR_USERS, AGR_AGRS, AGR_DEFINE, AGR_TEXTS, UST04, UST12, USOBT
SYSTEM & CONNECTIVITY (the attacker's map):
RFCDES, PAHI, TPARAM, E070, E071, T000, SNAP, RSAU_BUF_DATA, DD03L
FINANCIAL / BUSINESS:
ACDOCA, BKPF, BSEG, LFA1, LFBK, KNA1, EKKO, EKPO, MARA, PA0008, REGUH
===========================================================================
STEP 4 - THE RECONNAISSANCE SIGNATURE. THIS IS THE KEY TEST.
===========================================================================
A read sequence touching IDENTITY + AUTHORIZATION + SYSTEM tables from a SINGLE
user and a SINGLE IP within a SHORT window is the textbook enumeration pattern.
Specifically: USR02 + UST04 + AGR_* + RFCDES + PAHI read together via RFC is a
security-posture sweep.
If you detect it, report it as HIGH - and then state plainly:
SM20 ALONE CANNOT DISTINGUISH AN AUTHORISED SECURITY SCANNER FROM AN ADVERSARY.
The records produced by a sanctioned vulnerability scanner, a GRC tool, an SAP
license measurement, an internal audit script, and a post-exploitation enumeration
are IDENTICAL. There is no field in SM20 that separates them.
Give the exact user, IP, full table list, timestamp window and read rate, so a
human can resolve it in one minute by confirming whether that account and that IP
belong to a sanctioned tool.
Do NOT assume benign. Do NOT assume malicious. Do NOT invent an audit-bypass claim
from the absence of a logon record. Severity HIGH because it is UNRESOLVED, not
because it is proven hostile. Confidence: Requires Correlation.
===========================================================================
STEP 5 - PRIVILEGED TRANSACTION USAGE
===========================================================================
Flag every AU3 start of:
User admin : SU01, SU10, SU53, PFCG, SUIM, SU24
Development: SE38, SE37, SE80, SE11, SE24, SE93, SA38
Table/data : SE16, SE16N, SE17, SM30, SM31, SM34
System : SCC4, SCC5, RZ10, RZ11, SM59, SM49, SM69, STMS, SM12, SM01
Audit : SM19, SM20, RSAU_CONFIG, RSAU_READ_LOG
Debug : /H, ST05, SE30
Report user, terminal, IP, client, time.
SE16N, SM30 and SE38 in a production client are HIGH: they bypass transaction-level
controls and application logic entirely. If you cannot determine which clients are
productive from the data, STATE THE ASSUMPTION rather than asserting it.
===========================================================================
STEP 6 - MACHINE ACCOUNT HYGIENE. Report each as PRESENT or ABSENT.
===========================================================================
a) DDIC or SAP* used as a BATCH JOB STEP USER (AU1 type B, source RSBTCRTE)
-> HIGH. This is NOT "expected" and NOT "normal". Standard SAP accounts must
not run jobs: attribution breaks (every job action logs as DDIC) and password
rotation breaks (rotating DDIC breaks every job). Do not excuse it on the
grounds that the logon type is not dialog.
b) Any account with >1,000 logons in the window -> report rate per hour and whether
it is CONSTANT (scheduled job) or BURSTY.
c) AUY download-to-file events -> data leaving the system. List user, byte count,
filename. Any download by a privileged or service account is HIGH.
d) A service account appearing from MORE THAN ONE source IP -> shared or replicated
credentials.
e) Any DUAL-USE account from STEP 2 -> restate it here.
===========================================================================
STEP 7 - OUTPUT
===========================================================================
TABLE A - Account Inventory:
User | Classification (Standard SAP / Machine / Human / DUAL-USE) | Total Events |
Logon Types | Source IPs | Clients | Privileged TCodes Used | Sensitive Tables Read |
Risk Rating | Reasoning
TABLE B - Table Access Register:
User | Peer IP | Access Method (RFC / Internal) | Table | Category (Identity /
Authorization / System / Financial / Business) | Activity (Display 03 / Change 02) |
Read Count | First Read | Last Read | Recon Sequence (Y/N) | Risk Rating
Sort Table B by Risk Rating, then Category (Identity first), then Read Count desc.
Finish with a section titled:
"Access that cannot be explained by the log alone"
List every account or IP whose behaviour is legitimate-OR-hostile, and state
exactly what external fact would settle it.
===========================================================================
RULES
===========================================================================
- Never conclude an account is benign because it has an ordinary-looking name.
- Never conclude an account is malicious because it read sensitive tables.
Report the read, report the pattern, and name the fact needed to decide.
- If an authorised scanning tool would produce identical records, SAY SO.
- Never infer audit-trail evasion from a missing record.
- Run the dual-use check on every account, without exception.
Why ‘dual-use’ is checked on every account, no exceptions
This check is mechanical because judgement is exactly where it fails. A service account that also logs on interactively is easy to miss — the interactive logons are a handful of records buried in machine noise, and an analysis that overlooks them can read the apparent absence as something sinister ("the RFC connection bypassed the audit trail") while the real finding sits in plain sight: the account is dual-use. So the check runs on every account regardless of how ordinary it looks — machine-type activity plus a human logon type equals dual-use, full stop. That combination destroys attribution, because every action either side takes lands under the same user ID. The fix is equally mechanical: set the user type to SYSTEM or SERVICE so interactive logon stops being possible.
Beyond a one-time snapshot
These prompts are a one-time read of an exported log. Syntasec does it live and continuously across your entire SAP landscape — correlating SM20 with change documents, role assignments, and system parameters, so the questions these prompts have to leave open ("what actually changed?", "is this scanner sanctioned?") are already answered.
Want the SM20 reducer script and the privileged-transaction watchlist as a ready-to-run file?
Optional. The prompt above is fully readable and copyable whether or not you use this.
Frequently asked questions
Why does SM20 flag an account as "dual-use", and why does it matter?
Dual-use means one account shows both machine-type activity (a batch, RFC, or service logon type) and a human interactive logon (dialog or Fiori). That combination destroys attribution — every action the interface performs and every action a person performs using the same credentials land under one identical user ID in every log you own. The fix is mechanical too: set the account’s user type to SYSTEM or SERVICE so interactive logon becomes impossible, and rotate the password.
Who read USR02 (the SAP password hash table), and is that a problem?
Not automatically — USR02 is legitimately read by user administration tools, GRC, and license measurement. It becomes a finding when the read comes via RFC (CUZ) from an account and IP that also touched authorization tables (AGR_*, UST04) and connectivity tables (RFCDES, PAHI) in the same short window. That combination is the textbook SAP reconnaissance sweep — whether it’s a sanctioned scanner or something else is exactly the question this prompt surfaces for a human to answer.
Is DDIC running a batch job a security problem?
Yes, and it’s a finding regardless of the logon type. Standard SAP accounts like DDIC or SAP* running as a job step user break attribution — every job action logs as DDIC, not as whoever scheduled it — and block clean password rotation, since rotating DDIC’s password breaks every job that runs under it. It’s a common, long-standing configuration issue, not something to wave off as expected behaviour.
Can SM20 tell whether a table read was a sanctioned security scan or an attacker?
No — this is worth repeating because it’s the most commonly overstated claim in SM20 analysis. A sanctioned vulnerability scanner, a GRC assessment, a license audit, and a post-exploitation enumeration script produce identical read patterns across identity, authorization, and system tables. The honest output names the exact account, IP, table list, and time window so a human can confirm in a minute whether that combination belongs to an approved tool.
What privileged transactions should I watch for in SM20?
The high-value ones are the ones that bypass application-layer controls entirely — SE16/SE16N and SM30 direct table maintenance, SE38/SA38 program execution, and PFCG/SU01 role and user administration — especially when they run in what looks like a production client. SM20 records the transaction start; whether the client is genuinely production is something you may need to state as an assumption if the export doesn’t make it explicit.
Is it safe to paste privileged-access and RFC log data into an AI model?
Not into a public one. This is arguably the most sensitive class of SM20 export — it shows exactly which accounts read password-hash and authorization tables, from which IPs, which is personal data under GDPR and equivalent regimes and, in the wrong hands, a useful map of your own systems. Anonymise the account and IP fields before using a public model, or keep the analysis inside your own infrastructure. Syntasec runs entirely on the customer's own infrastructure and is LLM-agnostic, so this data never has to leave your network.