ABAP Custom Code Vulnerabilities (Z/Y Objects)
Customer-developed Z/Y ABAP (reports, function modules, classes, BSP/Web Dynpro applications) frequently reintroduces vulnerability classes the SAP kernel and Open SQL already protect against - because the developer opted into a dynamic or native construct. A white-box code review with developer/read authorizations (S_DEVELOP etc.) hunts these sinks via SE38/SA38/SE80 source display, RS_ABAP_SOURCE_SCAN pattern search, a REPOSRC table dump (Base64-encoded DATA column - diffable against transport history to catch code that bypassed CTS entirely), SCI/ATC (SAP Code Vulnerability Analyzer, per SAP Note 1921820), or an offline SAST tool such as the OWASP ABAP Code Scanner. Every finding below is customer-reproducible: the review targets the customer’s own custom code, not an SAP-shipped 0day.
Depending on the sink, impact ranges from information disclosure to full remote code execution at the ABAP-VM layer (GENERATE SUBROUTINE POOL, dynamic dispatch), the OS layer (CALL 'SYSTEM', SXPG_*), or the database layer (EXEC SQL/ADBC, which bypasses all SAP-layer protections - Open SQL buffering, table-change logging, and ABAP authorization checks). Missing or broken AUTHORITY-CHECK - the single most common finding class - lets any user who can reach the transaction, report, or RFC-enabled function module perform the action regardless of SAP role. Hard-coded secrets and sy-uname-gated backdoors enable lateral movement and persistent, review-resistant access. Because custom code runs with the full privileges of the calling work process and its DB connection, these findings routinely compromise confidentiality, integrity, and availability well beyond the object where they were found.
Discovery workflow (lead with the tool, not manual reading):
RS_ABAP_SOURCE_SCAN(viaSE38) - pattern-based source scan across custom Z/Y programs/includes/function groups; the primary discovery tool for every sink below.REPOSRC- raw table dump of all ABAP source (Base64DATAcolumn); diff against transport history to catch code written directly to the table, bypassing CTS.- SCI / ATC (Code Inspector / ABAP Test Cockpit) - automates many of the same pattern checks via the SAP Code Vulnerability Analyzer (SAP Note 1921820).
- OWASP ABAP Code Scanner (RedRays) - free, offline SAST for exported ABAP source; published check categories: Injection (XSS/SQLi/directory traversal), Secrets (hard-coded credentials/keys), Cryptography (weak/outdated algorithms), Best practices (insecure dynamic statements).
#EC CI*pseudo-comment density - marks a suppressed CVA/ATC finding; treat clustering around injection-class checks as requiring manual re-verification.
Sinks and their secure alternative:
| Sink (search pattern) | Class | Secure alternative | CWE |
|---|---|---|---|
SELECT (dyn_cols) FROM (dyn_table) / dynamic WHERE (dyn_cond) / INSERT INTO (dyn_table) / DELETE FROM (dyn_table) | SQL injection (dynamic Open SQL) | Allow-list via CL_ABAP_DYN_PRG=>CHECK_TABLE_NAME_STR / CHECK_WHITELIST_TAB; never build table/field/WHERE text from unrestricted input | CWE-89 |
EXEC SQL … ENDEXEC / dynamic CL_SQL_STATEMENT/CL_SQL_CONNECTION (ADBC) | Native SQL / ADBC injection - bypasses all Open SQL protections, authorization checks, and change logging | Avoid Native SQL for application logic; bind variables (:host_var) only, never dynamic statement text | CWE-89 |
CALL 'SYSTEM' (undocumented kernel call) | OS command injection - RCE as <sid>adm | Never use in custom code; disable via rdisp/call_system | CWE-78 |
SXPG_COMMAND_EXECUTE / SXPG_STEP_XPG_START / SXPG_CALL_SYSTEM with a dynamically built command/parameter | OS command injection | SM69-defined fixed commands only, no free-text parameter passthrough; enforce S_LOG_COM/S_C_FUNCT | CWE-78 |
CALL 'ThWpInfo' ID 'OPCODE' … (Linux-only kernel call) | OS command injection, backdoor-grade | Never legitimate in custom code; treat any occurrence as a backdoor finding | CWE-78 |
GENERATE SUBROUTINE POOL <itab> NAME <subpool> where <itab> is populated from user/RFC input | ABAP code injection - arbitrary source executed with no further authorization check | Never generate/execute code from external input; sandbox and strictly whitelist syntax if unavoidable | CWE-94 |
INSERT REPORT <name> FROM <itab> (after READ REPORT/EDITOR-CALL) | Persistent backdoor - writes executable code directly to REPOSRC, bypassing the transport system | Restrict S_DEVELOP OBJTYPE=PROG ACTVT=01/02; never reachable from a user-controlled program-name/source parameter | CWE-94 |
Dynamic PERFORM … IN PROGRAM (…) / CALL METHOD (…) / CALL FUNCTION (…) with an unsanitized target name | ABAP code injection - arbitrary subroutine/method/FM dispatch | Static dispatch, or validate the target name against a hard-coded allow-list | CWE-94 |
Commented-out source reassembled at runtime via READ REPORT + SHIFT/REPLACE + INSERT REPORT/GENERATE SUBROUTINE POOL | Steganographic backdoor - passes casual review since comments are skipped | Ban self-modifying-code patterns via secure-coding guideline; ATC custom check for READ REPORT + INSERT REPORT co-occurrence | CWE-94 / CWE-912 |
OPEN DATASET <dyn_path> FOR OUTPUT/INPUT / TRANSFER … TO <dyn_path> / READ DATASET <dyn_path> | Directory traversal - arbitrary application-server file read/write | FILE_VALIDATE_NAME (SAP Note 1497003) plus logical file names (FILE/SFILENAME) instead of raw physical paths; AUTHORITY-CHECK on S_DATASET/S_PATH before every file operation | CWE-22 |
Sensitive logic with no AUTHORITY-CHECK at all | Missing authorization check | Add AUTHORITY-CHECK OBJECT for every sensitive business object and branch on sy-subrc | CWE-862 |
AUTHORITY-CHECK present but sy-subrc never evaluated | Broken authorization check - silent no-op | Always branch on sy-subrc <> 0 immediately after the check | CWE-862 |
AUTHORITY-CHECK … FOR USER <var> with attacker-influenceable <var> | Authorization decision made for the wrong user | Never parameterize FOR USER from external input | CWE-863 |
IF sy-uname = '<hardcoded_user>' gating a security-relevant branch (e.g. skipping AUTHORITY-CHECK, enabling EDITOR-CALL/INSERT REPORT) | sy-uname backdoor - a named account bypasses controls normal users face | Never branch security-relevant logic on sy-uname; a critical finding regardless of stated intent | CWE-912 |
Dynamic CALL TRANSACTION <dyn_tcode> without the WITH AUTHORITY-CHECK addition | Insecure CALL TRANSACTION | Always use CALL TRANSACTION … WITH AUTHORITY-CHECK | CWE-862 |
Remote-enabled custom Z/Y function module with no AUTHORITY-CHECK for the business objects it touches | Missing authorization in an RFC-enabled FM - reachable by any caller with generic S_RFC (see Critical RFC-Enabled Function Modules) | Mandate AUTHORITY-CHECK inside every remote-enabled custom FM; scope S_RFC/S_RFCACL tightly rather than relying on an over-privileged interface user | CWE-862 |
Custom report executable via SA38/SE38 with no P_GROUP authorization group / no dedicated transaction | Access-control bypass of the transaction layer | Assign an S_PROGRAM authorization group, wrap in a dedicated tcode (SE93), and restrict direct SA38/SE38 execute access to developers | CWE-284 |
Hard-coded password/API-key/username literal (CALL FUNCTION 'RFC_...', HTTP client setup, CONNECT TO) | Hard-coded secrets - readable via S_DEVELOP source display or, via REPOSRC, even without ABAP authorizations | Retrieve from Secure Storage (CL_SECSTORE_CONFIG/SSF) or a secrets manager instead - see Decrypting SAP Secure Storage for how attackers extract what’s stored there; never hard-code | CWE-798 |
User-controlled value (e.g. cl_wd_runtime_services=>get_url_parameter) written to BSP/Web Dynpro/ITS output without encoding | Reflected/stored XSS | Encode all dynamic output with ABAP’s ESCAPE() function (or the BSP/Web Dynpro output-encoding API); treat every URL/form parameter as untrusted | CWE-79 |
Hard-coded BREAK-POINT left in production code, or broad S_DEVELOP OBJTYPE=DEBUG ACTVT=02 (“debug with replace”) on non-emergency roles | Debugger exposure - debug-with-replace can directly overwrite variable contents mid-transaction, including sy-subrc right after a failed AUTHORITY-CHECK | Remove all BREAK-POINT statements before transport; restrict debug-with-replace to a monitored firefighter/emergency-user process; NW 7.57+ offers the finer-grained S_DBG object | CWE-489 |
- Adopt a secure ABAP coding guideline that explicitly covers every sink class above, and enforce it via mandatory SCI/ATC (SAP Code Vulnerability Analyzer) checks before transport release.
- Treat
#EC CI*suppression clusters - especially around injection-class checks - as requiring documented, reviewed justification, not a rubber stamp. - Run the OWASP ABAP Code Scanner (or equivalent offline SAST) over exported source as a CI gate, complementing SCI/ATC.
- Never build dynamic Open SQL, Native SQL/ADBC statement text, OS commands, or generated ABAP source from unsanitized input; use the allow-list/bind-variable alternatives in the table above.
- Mandate
AUTHORITY-CHECKwith explicitsy-subrcbranching everywhere, including inside remote-enabled custom function modules; scopeS_RFC/S_RFCACLtightly instead of relying on broad interface-user grants. - Store secrets in Secure Storage or a secrets manager, never hard-coded; rotate any credential found during a review.
- Restrict
S_DEVELOP OBJTYPE=DEBUG ACTVT=02to a monitored, change-controlled process; strip allBREAK-POINTstatements before go-live. - See ABAP Code Review Process for the review workflow this catalog feeds into, and Code Verification for confirming whether a found backdoor is live - this page is about finding vulnerable/backdoored code, not verifying an implant.
- ABAP Code Review Process
- Code Verification
- OS command execution
- Critical RFC-Enabled Function Modules
- Decrypting SAP Secure Storage
- SAP Note 1497003 -
FILE_VALIDATE_NAME/ directory traversal protection - SAP Note 1921820 - SAP Code Vulnerability Analyzer check list
- SAP ABAP Keyword Documentation, “Security Risks in Dynamic ABAP Programming” (help.sap.com,
abendynamic_programming_scrty.htm) - OWASP ABAP Code Scanner (RedRays)
- Pradeep Kumar Mishra, SAP® System Security, SAP PRESS, 2026 - ch.7.1.2 “Custom Code Vulnerabilities”
- Daniel Berlin, SAP-Systeme schützen, SAP PRESS / Rheinwerk Verlag, Bonn 2017 - ch.12.4 “Angriffe auf SAP-Datenbanken”
