Join our Newsletter — 33% off our NHI Course
Home› Guides› OWASP Top 10 A05 Guide: Injection (2025): Separating…
Guide Web & API Security

OWASP Top 10 A05 Guide: Injection (2025): Separating Code From Data

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 26 October 2026 14 min read
On this page

Injection happens whenever untrusted data reaches an interpreter and changes the structure of the command it runs, and it still produces more CVEs than any other OWASP Top 10 category. In the OWASP Top 10:2025, injection is A05:2025 Injection, down from third place in 2021 but still tested in every application OWASP received data for. This guide goes one level deeper than our overview: what the category actually contains, the defence for each interpreter, how to roll out and prove those defences, and where machine identities make injection worse. It is written for application security engineers, developers who own data access and build pipelines, and assessors who need evidence rather than assurances.

Key takeaways

  • Separate code from data, every time. Parameterised queries, argument arrays for OS calls and context-aware output encoding fix the root cause; input validation and WAF rules only reduce it.
  • The category is wide. OWASP maps 37 CWEs to A05:2025, including cross-site scripting (CWE-79), SQL injection (CWE-89), OS command injection (CWE-78), LDAP, XPath, code, CRLF and template injection.
  • Identifiers and escape hatches are where teams fail. Table names, column names, sort orders, JSON keys and framework bypasses such as React's dangerouslySetInnerHTML cannot be parameterised and need allow-list mapping or removal.
  • The database account sets the blast radius. A successful injection runs with the privileges of the application's service account, so least privilege for that non-human identity decides whether one flaw becomes a full data breach.
  • Eliminate the class, not the instance. CISA and the FBI ask manufacturers to remove injection as a whole class through safe libraries, banned-call rules in pull requests and continuous testing, rather than fixing bugs one by one.

What it is and who it applies to

OWASP defines injection as a flaw where untrusted input is sent to an interpreter (a browser, a database, a command line) and the interpreter executes part of that input as a command. An application is vulnerable when user-supplied data is not validated or sanitised, when dynamic queries or non-parameterised calls are used without context-aware escaping, when unsanitised data is passed into ORM search parameters, or when hostile data is concatenated into SQL or commands so that it alters their structure.

The 2025 data explain why this still matters. OWASP reports a maximum incidence rate of 13.77%, an average of 3.08%, 1,404,249 occurrences and 62,445 CVEs, the most of any category. The two biggest contributors pull in opposite directions: cross-site scripting has more than 30,000 CVEs (high frequency, lower impact) and SQL injection more than 14,000 (lower frequency, high impact). Prompt injection against large language models is deliberately out of scope here and covered by LLM01:2025. See the OWASP LLM Top 10 LLM01 Prompt Injection Guide.

  • Who it applies to: any team that builds or buys software which constructs queries, commands, markup, templates or expressions from data it did not fully control, including internal tools, admin consoles, APIs and CI/CD workflows.
  • Where it lands in practice: web and API back ends (SQL, NoSQL, ORM, LDAP), front ends (DOM and reflected XSS), edge and network appliances (OS command injection in management interfaces), and build systems (script injection in pipeline definitions).
  • How it relates to the rest of the list: the OWASP Top 10 is an awareness document, not a standard. For testable requirements use OWASP ASVS 5.0, chapter V1 Encoding and Sanitization. See the OWASP Top 10 Guide and the OWASP ASVS Guide.

Structure and key requirements

The category groups many interpreters, but the defence pattern is the same: keep the structure of the command fixed in code, pass data through an interface that cannot change that structure, and treat anything that cannot be bound as a fixed choice from an allow-list.

Injection typeRepresentative CWEPrimary defenceASVS 5.0 requirement
SQL, HQL, NoSQL, CypherCWE-89Prepared statements with bound parameters, or an ORM used without raw string fragmentsV1.2.4 (L1)
OS commandCWE-78, CWE-77Use a library API instead of a shell; if a process must be launched, pass an argument array with no shellV1.2.5 (L1)
Cross-site scriptingCWE-79Framework auto-escaping plus context-specific output encoding; sanitise user-authored HTMLV1.2.1, V1.2.3 (L1)
LDAPCWE-90LDAP-specific encoding of filter values; fixed filter structureV1.2.6 (L2)
XPathCWE-643Parameterised or precompiled XPath queriesV1.2.7 (L2)
Code and expression languageCWE-94Avoid eval() and dynamic expression evaluation such as SpEL on user inputV1.3.2 (L1)
Server-side templateCWE-94 familyNever build templates from untrusted input; pass data as template variablesV1.3.7 (L2)
CRLF and HTTP response splittingCWE-93, CWE-113Framework header APIs that reject CR and LF; never write raw headersV1.2.1 (header context)

SQL and other database queries

The OWASP SQL Injection Prevention Cheat Sheet orders the defences: prepared statements with parameterised queries first, then stored procedures (safe only if any dynamic SQL inside them also binds its values), then allow-list validation for elements that cannot be bound, and finally escaping, which it strongly discourages because escaping rules depend on dialect and configuration (MySQL's NO_BACKSLASH_ESCAPES mode changes them). Parameter markers cannot bind table names, column names or keywords such as ASC and DESC, so the user's choice must be mapped to an application-owned literal and anything unknown rejected. The same applies to JSON keys and filter field names passed through to a query builder: the McKinsey AI platform hack involved an endpoint whose values were parameterised but whose JSON field names were concatenated into SQL, and standard scanners did not flag it. See the SQL Injection Prevention Guide.

NoSQL stores have their own form of the problem: when a request body is passed straight into a query object, an attacker can supply an operator instead of a value. Bind values to typed fields and reject objects where a scalar is expected.

OS commands

The CISA and FBI Secure by Design alert on OS command injection cites CVE-2024-20399, CVE-2024-3400 and CVE-2024-21887, all in network edge devices and all reachable by unauthenticated attackers. Its guidance is to use built-in library functions that separate commands from their arguments rather than building command strings, to limit which parts of a command user input can influence, and to enforce this with pull request rules that block risky calls such as os.system, string-based subprocess.run and shell=True. See the Command Injection Guide.

Cross-site scripting

Modern frameworks escape output by default, so XSS now concentrates in the escape hatches: React's dangerouslySetInnerHTML, Angular's bypassSecurityTrustAs* functions and Lit's unsafeHTML. The OWASP XSS Prevention Cheat Sheet adds that encoding does not reliably protect data placed inside script blocks, HTML comments, style blocks or functions such as eval() and setTimeout(); prefer textContent over innerHTML, sanitise user-authored HTML with a maintained sanitiser such as DOMPurify, and treat Content Security Policy (ASVS V3.4.3) as defence in depth, not the fix. See the Cross-Site Scripting (XSS) Prevention Guide.

Templates and pipeline definitions

Server-side template injection occurs when user input becomes part of the template rather than a variable passed to it. See the Server-Side Template Injection (SSTI) Guide. CI/CD workflows are an often-missed interpreter: GitHub's documentation lists context values such as pull request titles and bodies, head_ref, ref and commit messages as untrusted, and explains that expressions are substituted before the shell runs, so a crafted title or branch name becomes shell code on the runner.

Identity and NHI requirements

Injection is a code flaw, but the damage it causes is set by identity. Every injected query, command or script runs as some non-human identity: the database login in the connection string, the operating system account of the application process, or the token held by the build runner.

InterpreterIdentity the attacker inheritsControl that limits the blast radius
Relational or NoSQL databaseApplication database accountOne account per application and function; no DBA, owner or DDL rights; grant on views or stored procedures only (ASVS V13.2.2)
Operating system shellService account of the web or worker processRun as a dedicated unprivileged account; no interactive login; read-only file system where possible; no cloud credentials in environment variables
LDAP directoryBind account used for lookupsRead-only bind scoped to the needed organisational unit; no write or password-reset rights
CI/CD runnerWorkflow token and any stored secretsRead-only default token permissions; secrets only in jobs that need them; short-lived OIDC federation instead of stored keys
Browser (XSS)The victim user's sessionHttpOnly and SameSite cookies, short sessions, re-authentication for sensitive actions
  • Least privilege for database accounts: the OWASP cheat sheet is explicit that application accounts must never hold DBA or admin access, and recommends separate accounts per application so that, for example, a login function only reads credential fields. See the OWASP NHI Top 10 NHI5 Overprivileged NHI Guide.
  • Secrets reachable from the process: command injection usually leads straight to environment variables, configuration files and instance metadata. Keep long-lived keys out of the process and prefer workload identity. See the OWASP NHI Top 10 NHI7 Long-Lived Secrets Guide.
  • Pipeline tokens: in the Ultralytics PyPI compromise, a branch name was inserted into a shell script in a privileged pull_request_target workflow, and a long-lived PyPI API token that had not been revoked was later used to publish further malicious releases. See the GitHub and GitHub Actions Security Guide.

Implementation steps

  1. Inventory interpreter sinks. Use SAST or a simple code search to list every place the code builds SQL, shell commands, LDAP filters, XPath, templates, expression-language strings or raw HTML. Include stored procedures that build dynamic SQL and CI workflow files.
  2. Set the safe defaults. Publish an approved data-access layer (parameterised driver or ORM), a process-execution wrapper that takes argument arrays only, and a front-end rule that forbids escape-hatch APIs except through a reviewed sanitiser. Document dangerous functionality as ASVS V15.1.5 expects.
  3. Add banned-call rules in audit mode. Introduce SAST or linter rules for string-concatenated queries, os.system, shell=True, eval(), dangerouslySetInnerHTML and untrusted expressions in workflow run steps. Run them in report-only mode for two to four weeks to size the backlog and tune false positives.
  4. Fix by risk. Start with internet-facing and unauthenticated endpoints, then admin functions, then internal tools. Replace concatenation with binding; replace user-supplied identifiers with allow-list mapping; remove shells.
  5. Shrink the identity behind each sink. Split shared database logins, remove DDL and admin rights, and move pipeline secrets to short-lived credentials. Test in a staging environment by running the application's regression suite against the reduced grants.
  6. Turn rules into gates. Once the backlog for a repository is cleared, switch banned-call rules to blocking on pull requests. Allow exceptions only with a recorded reviewer and expiry.
  7. Test continuously. OWASP recommends combining source code review with automated testing and fuzzing of all parameters, headers, URLs, cookies, JSON and XML inputs, with SAST, DAST and IAST in the pipeline.
  8. Plan the rollback. Ship query and command changes behind feature flags where practical, keep the previous release deployable, and if a reduced database grant breaks a function, restore only the specific grant needed and log the exception rather than reinstating the old shared account.
  • Small organisations: rely on framework defaults and one maintained SAST tool with banned-call rules; the biggest win is usually removing raw SQL and shell calls entirely.
  • Large organisations: provide a paved-road data-access library, central rule packs, and per-application database accounts provisioned automatically. Track exceptions centrally. See the Secure Coding Guide and the DevSecOps Guide.
  • WAF or code fix: use a WAF or WAAP rule as a temporary shield while a fix ships or for third-party software you cannot change; never as the permanent control for code you own.

Evidence and assessment

Assessors should expect evidence that the defence is systematic, not that a single penetration test found nothing.

EvidenceWhat good looks likeSource
Coding standardMandates parameterisation, argument arrays and context encoding; names banned APIsSecure coding policy, ASVS V1.2
SAST resultsInjection rules enabled and blocking on merge; open findings within remediation targetsPipeline reports
DAST or IAST resultsAuthenticated scans covering APIs and all input types, not only HTML formsScanner reports
Manual test coverageInjection test cases from the OWASP Web Security Testing Guide input validation section executed for high-risk functionsPenetration test report
Database grantsPer-application accounts, no admin or DDL rights, reviewed at least annuallyGrant exports, access review records
LoggingRejected input and validation bypass attempts logged (ASVS V16.3.3) and sent to the SIEMLog samples, detection rules

Detection signals: database error spikes from a single client, SQL syntax errors in application logs, web server processes spawning shells or network utilities, unexpected outbound connections from application hosts, new files in web roots (a common follow-on, ATT&CK T1505.003 Web Shell), and CSP violation reports that point to inline script.

  • Metric 1: number of interpreter sinks still using concatenation, trending to zero per application.
  • Metric 2: percentage of repositories with injection rules in blocking mode.
  • Metric 3: median time to remediate high-severity injection findings against the documented target.
  • Metric 4: percentage of application database accounts with no admin, owner or DDL rights.
  • Metric 5: injection findings reaching penetration tests or bug bounty, which should fall as pipeline gates mature.

Mapping to other frameworks

FrameworkReferenceRelevance to injection
OWASP ASVS 5.0V1.2.1 to V1.2.7, V1.3.2, V1.3.7Testable output encoding, query and command parameterisation, template and eval controls
NIST SP 800-53 Rev. 5SI-10 Information Input Validation; SA-11 Developer Testing and Evaluation; SA-15 Development Process, Standards, and Tools; AC-6 Least PrivilegeValidation, testing in the SDLC, mandated tooling and least-privilege service accounts
NIST CSF 2.0PR.PS-06; ID.RA-01; DE.CM-09Secure development practice, vulnerability identification and runtime monitoring
CIS Controls v8.1Control 16 Application Software SecuritySecure development life cycle for in-house and acquired software (mapped at control level)
ISO/IEC 27001:2022 Annex A8.26 Application security requirements; 8.28 Secure coding; 8.29 Security testing in development and acceptanceRequirements, coding standard and testing evidence
MITRE ATT&CK v20T1190 Exploit Public-Facing Application; T1059.004 Unix Shell; T1505.003 Web ShellInitial access through injection, command execution and persistence that follows
MITRE CAPECCAPEC-66 SQL Injection; CAPEC-88 OS Command Injection; CAPEC-63 Cross-Site Scripting (XSS)Attack patterns for threat modelling and test design

Common pitfalls

  • Parameterising values but not identifiers: sort fields, column lists, table names and JSON keys concatenated into otherwise safe queries, as in the McKinsey case above.
  • Trusting the framework blindly: OWASP's own scenario shows HQL concatenation defeating an ORM; frameworks protect only the paths you use as designed.
  • Stored procedures that build dynamic SQL: the call is bound, but the procedure concatenates internally.
  • Relying on input validation or a WAF: OWASP notes positive validation is not a complete defence because many applications legitimately need special characters.
  • Forgetting non-web interpreters: CI workflow expressions, LaTeX processors (ASVS V1.2.8), regular expressions (V1.2.9) and management interfaces on appliances.
  • Shared, over-privileged service accounts: one injectable endpoint then exposes every schema the shared login can read.

Practitioner checklist

  • List every interpreter sink in each application, including stored procedures and CI workflow files.
  • Require parameterised queries or an approved ORM for all data access; ban string-built queries.
  • Map every user-chosen identifier (sort, column, table, JSON key) to an application-owned allow-list.
  • Replace shell calls with library functions or argument arrays; block os.system, shell=True and eval() in pull requests.
  • Restrict front-end escape hatches to a reviewed sanitiser and deploy a tuned Content Security Policy.
  • Pass untrusted workflow context through environment variables, never directly into run steps.
  • Give each application its own least-privilege database account with no admin or DDL rights.
  • Run SAST, DAST and fuzzing in the pipeline and move injection rules to blocking once the backlog is cleared.
  • Log validation failures and alert on database errors, unexpected child processes and web root changes.
  • Report the five metrics above to engineering leadership each quarter.

Standards and references

Related NHI Mgmt Group resources: OWASP Top 10 Guide · SQL Injection Prevention Guide · Input Validation and Output Encoding Guide · Secure Code Review Guide · OWASP NHI Top 10 NHI5 Overprivileged NHI Guide

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 26 October 2026. Spotted an error? Use our contact page.
NHI Mgmt Group — the #1 independent authority on Non-Human Identity, IAM, and Agentic AI security. nhimg.org