OWASP Top 10 for systems analysts

Train for your next tech interview
1,500+ real interview questions across engineering, product, design, and data — with worked solutions.
Join the waitlist

Why a systems analyst needs OWASP

The OWASP Top 10 is the industry shortlist of the most exploited web vulnerabilities, and on a senior systems analyst interview at Stripe, Microsoft, or any fintech you can count on it appearing. You will not be asked to exploit anything. You will be asked how you turn each category into a non-functional requirement engineering implements without arguing — a different skill from knowing the names.

The classic failure mode is an analyst who writes "the system must support authorization" and considers the security section done. The team builds JWT-based auth, ships, and a pentest finds that user A can read user B's invoices by changing one digit in the URL. That vague line just cost a one-month rework plus a security incident report.

Load-bearing trick: every OWASP category in the spec must end with a verifiable acceptance criterion. Not "passwords are stored securely" but "passwords are stored using argon2id with memory cost ≥ 19 MiB and unique per-user salt; verified by a test asserting the stored hash is not equal to the plaintext".

A junior is expected to name the categories. A middle should explain each in plain English with a typical attack. A senior translates each into spec language with measurable acceptance criteria, plus names the team they loop in for review.

Broken access control and IDOR

This is A01 in the 2021 OWASP list and has held the top spot since. The common form is IDOR (Insecure Direct Object Reference) — the server checks the caller is logged in but never checks the object belongs to them.

GET /api/orders/123    → caller's own order, returns 200 OK
GET /api/orders/456    → another user's order, also returns 200 — BUG

Switching to UUIDs makes brute-forcing harder but is not a fix. The fix is an explicit ownership check on every read and write: "is the object owned by the principal in the current session, or has the principal been granted explicit access?" This lands as a service-layer guard or a row-level security policy in the database.

For the spec: "every API accepting a resource identifier must verify the authenticated principal has access to that specific resource; absence of an ownership claim returns 404 rather than 403 to avoid enumeration." That sentence is what an engineer can turn into code without a second meeting.

Injection

A03. The user supplies a string, the application concatenates it into a query, and the interpreter — SQL, shell, LDAP, NoSQL, XPath, a templating engine — runs it.

# bad: string concatenation
cursor.execute("SELECT * FROM users WHERE id = " + user_input)
# attacker submits user_input = "1; DROP TABLE users--"
# good: parameterized query
cursor.execute("SELECT * FROM users WHERE id = %s", (user_input,))

Most modern ORMs parameterize by default, so analysts assume injection is solved. It is not. The remaining surface is raw SQL, dynamic table or column names, LIKE searches with unescaped wildcards, and any place user input ends up inside an identifier. Server-side template injection (SSTI) in Jinja or Velocity is a fast-growing variant — if a marketing tool lets users write {{ variable }}, you have a remote code execution surface unless it is sandboxed.

For the spec: "all query parameters are passed via prepared statements or parameterized API calls; user input is never used to construct SQL identifiers, table names, or shell commands; templating engines that accept user-authored templates run in a sandbox with no filesystem or network access."

Cryptographic failures

A02. Crypto is rarely broken because the math is wrong. It is broken because it is used wrong. The pattern repeats across every postmortem.

Failure Why it happens Spec language to prevent
Plaintext or MD5/SHA-1 passwords Devs reuse an internal hashing helper from 2014 "Passwords stored with argon2id or bcrypt cost ≥ 12, never MD5/SHA-1/SHA-256"
Hardcoded symmetric key Key checked into git on day one of the project "All keys loaded from KMS or Vault at runtime; build fails if git-secrets finds a key pattern"
TLS 1.0/1.1 still enabled Legacy mobile client compatibility "TLS 1.2+ only; weak ciphers disabled per Mozilla intermediate profile"
Sensitive data in URL query strings Easier to test in Postman "PII and tokens travel in request body only, never in URL or HTTP referrer"
PII unencrypted at rest Engineers assumed disk encryption was enough "Column-level encryption for PII fields; key rotation documented"

Gotcha: disk-level encryption (LUKS, AWS EBS encryption) protects against a stolen physical drive. It does not protect against a leaked database dump. If a SQL injection or a misconfigured backup pulls the bytes out of the live database, those bytes are already decrypted. Column-level encryption with an external key is the only thing that helps in that scenario.

Identification and auth failures

A07. Authentication is built right ten times in a row and then broken in the eleventh because someone added "remember me forever" to win a usability ticket.

The recurring weak points are brute-force without rate limiting, default or weak credentials shipped with the system, predictable session identifiers, session fixation (the system reuses a pre-login session ID after login), and persistent sessions with no revocation path so a stolen token works for months.

The minimum baseline that should appear in any spec for a user-facing system:

  • Rate limiting on /login: 5 attempts per 15 minutes per email plus per IP, with exponential backoff on the user side.
  • Password policy: minimum 12 characters, blocklist against the top 10,000 leaked-password list (HIBP API or a local copy).
  • 2FA mandatory for any operation that moves money, changes the recovery email, or grants admin privileges. Optional but supported for normal login.
  • Session IDs: cryptographically random, ≥128 bits, regenerated on login and on privilege elevation, invalidated server-side on logout.
  • A documented session lifetime — typically 30 minutes idle / 12 hours absolute for SaaS, longer for low-risk consumer apps.

The spec should state each of these as a measurable threshold, not as a wish. "Login is secure" is not a requirement; "5 failed logins in 15 minutes returns HTTP 429 and triggers a security alert in Datadog" is one.

Train for your next tech interview
1,500+ real interview questions across engineering, product, design, and data — with worked solutions.
Join the waitlist

SSRF and XSS

A10 — Server-Side Request Forgery. The server fetches a URL supplied by the user, and an attacker uses that to reach internal infrastructure that has no public route.

# bad: server fetches whatever URL the user provides
fetch_url(user_provided_url)
# attack: http://169.254.169.254/latest/meta-data/iam/security-credentials/
#         pulls IAM credentials off the EC2 metadata service

SSRF is the vulnerability behind the 2019 Capital One breach (100M+ records). Defence is an allowlist of permitted domains, hard blocks on private IP ranges (10/8, 172.16/12, 192.168/16, 127/8, 169.254/16, IPv6 loopback and ULA), and a dedicated egress network so a compromised service cannot reach the internal control plane.

A03 also includes XSS — cross-site scripting. An attacker stores JavaScript in a field that the application later renders into the DOM of another user's browser, where it can read cookies, submit forms, or scrape data.

<!-- vulnerable: server renders user input as raw HTML -->
<div>Hello, {{ username }}</div>
<!-- attack: username = <script>fetch('/api/me').then(r=>r.json()).then(send)</script> -->

The fixes are output encoding by default in the templating engine, a strict Content Security Policy that forbids inline scripts, and HttpOnly plus Secure plus SameSite=Lax cookie flags so even a successful XSS cannot exfiltrate the session.

What to write in the spec

A minimum security checklist that every non-trivial spec should carry, regardless of how rushed the sprint is:

  • Authentication: mechanism (OAuth 2.0 / OIDC / SAML), 2FA scope, password policy, session lifecycle, logout semantics.
  • Authorization: RBAC or ABAC model, explicit ownership checks per endpoint, role-permission matrix as an appendix.
  • Input validation: allowlist where possible, length and format constraints, validation runs server-side regardless of client checks.
  • PII handling: which columns are sensitive, masking rules in logs and analytics, encryption at rest, retention period.
  • Audit log: which actions are logged (login, password change, role change, money movement, data export), who can read the logs, retention.
  • Rate limiting: per-user and per-IP limits on login, password reset, and any expensive endpoint.
  • Transport: TLS 1.2+ only, HSTS enabled, mixed-content forbidden.
  • Secrets: stored in Vault/KMS, rotation cadence, no secrets in environment variables of long-lived containers.
  • Supply chain: SBOM generated per build, dependency scanning in CI, blocked-package list maintained.

This is the floor, not the ceiling. A dedicated security review still needs to sign off on any spec that touches authentication, payments, or PII — the checklist exists so the review is about edge cases, not about why the spec forgot to mention TLS.

If you want to drill systems analyst interview questions like this every day, NAILDD is launching with 500+ problems across exactly this pattern.

Common pitfalls

The most common pitfall is the analyst who decides security is not their lane and leaves the section blank, expecting engineering to fill it in. They will not. They build the happy path, ship, and discover the gap during the first security review or the first incident. The analyst's job is to make sure the spec contains threats and countermeasures engineering can implement without inventing requirements on the fly.

A close second is assuming the ORM makes injection impossible. It does not. Any raw query, any dynamic table or column name, any LIKE '%...%' search with unescaped wildcards, and any templating layer that accepts user-authored templates reopens the door. Call out these specific surfaces in the spec and require code review for any raw query.

A third trap is using MD5 or SHA-1 (or plain SHA-256) for password hashing. All three are fast, which is exactly the wrong property — a modern GPU rig tests billions of candidates per second against a stolen hash database. The correct primitives are argon2id or bcrypt with a cost factor calibrated to 100-300 milliseconds per hash on production hardware, slowing brute-force by six orders of magnitude.

Returning stack traces from production endpoints is a smaller but very common leak. A 500 response with a full traceback tells an attacker your framework version, your ORM, often your file paths. The spec should require a generic error envelope with an opaque error_id — details only in server logs.

Finally, skipping audit logs for failed logins and privileged actions removes the only reliable signal you have during incident response. If an admin account was compromised at 2 a.m. last Tuesday, you need a log that says so. Enumerate event types, retention, and access control on the log store itself.

FAQ

Should a systems analyst run penetration tests?

No. Pentesting is a specialised role — internal red team or an external auditor like NCC Group or Bishop Fox. The analyst's job is upstream: write the spec so the system has explicit, measurable security requirements. When the pentest report lands, the analyst translates each finding into a backlog item, sizes the fix, and updates the spec so the same issue cannot recur.

Is the OWASP API Top 10 a different list?

Yes, and it matters more for API-first products. The web OWASP Top 10 (2021) targets browser-rendered apps. The OWASP API Top 10 (2023) focuses on backend APIs — BOLA (Broken Object Level Authorization) is essentially IDOR rebranded, broken object property level authorization covers mass-assignment bugs, excessive data exposure is the JSON-endpoint version of returning too many fields. If you ship a public API, study both.

What matters more — code-level or design-level vulnerabilities?

Design-level. Broken access control, business-logic flaws, missing rate limits, weak account-recovery flows — these are decided in the spec, not the code. SQL injection and XSS are mostly fixed by framework defaults; they still need a checkbox, but rarely fail at the design stage. A senior analyst spends most of their security budget on the design layer.

Who owns compliance with privacy regulations like GDPR or CCPA?

Legal and security own the policy. The analyst owns the implementation requirements in the spec — data classification, consent capture, deletion workflows, export endpoints, audit trail. Expect to be asked how you would write the spec for a "delete my account" feature that satisfies GDPR Article 17 without breaking foreign keys. That is a design question, not a legal one.

How does an analyst verify that engineering implemented the security requirements?

Three layers. First, acceptance criteria in the Definition of Done mapping one-to-one to spec lines — every security requirement has a test. Second, a security sign-off step before release so a security engineer reviews the diff. Third, continuous controls — dependency scanning in CI, periodic pentests, secret scanning on every commit. The analyst makes sure all three exist.

Is this article an official OWASP document?

No. It is a working analyst's interpretation of the OWASP Top 10 (2021) and the OWASP API Top 10 (2023). The canonical references are the OWASP Foundation's own documents, which should be the source of truth for spec language going into production.