46 questions
Web security interview questions and answers
Junior questions
1. In the admin panel only admins see the "Delete user" button. A tester logged in as a regular user takes the
DELETE /users/17request from an admin's DevTools, puts in his own token, and the user is deleted. What is missing and where should it be checked?Answer
The server checked authentication (the token is genuine, the user is known) but not authorisation, that is whether this particular user may perform this action. A hidden button in the UI protects nothing: the request can be sent directly from DevTools, curl or Postman. In OWASP API terms this is BFLA (broken function level authorization): there is no role check at the function level. The fix: permission checks on the server for every request, explicitly on every route (
requireRole('admin'), a guard, a policy) under the rule "denied until explicitly allowed". The answer in this case is403, not401, because the user is known.Follow-up question: How do you make sure a new admin endpoint cannot accidentally be left without a role check?
- Course: Auth and security
- Knowledge base: OAuth 2.0, JWT
- Source: owasp.org
2. In code review you see a user search where SQL is built with a template string:
emailfrom the request body is inserted intoWHERE, andsortfrom a query parameter intoORDER BY. The author says the email is validated on the frontend. What is wrong here and how do you rewrite it?Answer
This is SQL injection: user data becomes part of the query text, and a value such as
' OR '1'='1changes its structure. Frontend validation gives nothing, because the request can be sent with curl bypassing the UI. Values are passed as parameters separately from the SQL text, for exampledb.query('SELECT * FROM users WHERE email = $1', [email]), and the driver never interprets them as code. Column names and sort direction cannot be passed as parameters, sosortis checked against an allowlist (a map fromcreatedtocreated_at) and only a value from the map is inserted. A database account with minimal privileges limits the damage further.Follow-up question: How do you find other places like this in a 200 thousand line codebase without reading it all by hand?
- Course: Web application security
- Source: cheatsheetseries.owasp.org
3. A customer sent support a message containing
<img src=x onerror=...>. When an agent opened the ticket in a React admin panel, the script ran and created a new admin on her behalf. How did this happen if React escapes output, and what do you fix?Answer
This is stored XSS: the malicious HTML is stored on the server and runs in the browser of everyone who opens the ticket, with that person's session rights. React escapes text in JSX, so the hole is almost always in a bypass:
dangerouslySetInnerHTMLfor "formatted" text, anhrefwith ajavascript:URL, a directinnerHTML, or markdown rendered to HTML without sanitising. The fix: show the message as text, and if HTML is really needed, sanitise it with DOMPurify using a tag allowlist and check link schemes. The second line is a CSP withoutunsafe-inline, which will not run an inline handler. AnHttpOnlycookie stops session theft but does not help here: the script makes requests on the victim's behalf anyway.Follow-up question: Where would you look for reflected and DOM-based XSS in the same application?
- Course: Web application security
- Source: owasp.org
4. A user is logged in to your application, with the session in a cookie. They open a third-party site, which quietly submits a form
POST https://app.example.com/account/emailwith the attacker's address. The email is changed. Why did the browser allow this and how do you defend?Answer
This is CSRF: the browser attaches cookies to a request to your domain no matter who initiated it, and a simple form with
application/x-www-form-urlencodedneeds no preflight, so CORS does not help here (the attacker does not need to read the response). Defences:SameSite=LaxorStricton the session cookie, so the browser does not send it with a cross-sitePOST; a CSRF token in the form or a header that the other site cannot read; checkingOriginon state-changing requests. For changing an email or password, also re-confirmation: the current password or a message to the old address. An API that takes the token from theAuthorizationheader rather than a cookie is not vulnerable to CSRF, because the browser does not add that header on its own.Follow-up question: Does
SameSite=Laxprotect against every CSRF scenario?- Course: Web application security
- Source: cheatsheetseries.owasp.org
5. In code review you see passwords stored as
sha256(salt + password)with a unique salt per user. The author says: "there is a salt, so it is safe". Do you agree? What do you propose, and how do you migrate existing users?Answer
A salt only makes hashes different and defeats precomputed rainbow tables, but it does not slow brute force: SHA-256 is fast, one GPU computes billions of hashes per second, so after a database leak weak passwords are cracked within hours. Passwords need a slow function with a tunable cost: argon2id (the OWASP recommendation), scrypt or bcrypt; they generate the salt themselves and store the parameters in the hash string. Migration without a password reset: on the next login verify the old hash and rewrite it with the new one, and for users who do not log in, wrap the old hash (
argon2id(sha256(...))) and mark the scheme, so no weak hashes stay in the database. Reversible encryption does not fit either: with the key you get every password.Follow-up question: bcrypt only uses the first 72 bytes of a password. When does this become a problem and what do you do about it?
- Course: Auth and security
- Source: cheatsheetseries.owasp.org
6. A frontend developer "fixed" a CORS error by setting
Access-Control-Allow-Origin: *on the API, and when that did not work with cookies, made the server echo back whateverOriginarrived together withAccess-Control-Allow-Credentials: true. Is this a hole? And did the old strict CORS protect the API from an attacker using curl?Answer
CORS does not protect the server: it is a browser rule that decides whether a script from another origin may read the response. Curl, Postman or the attacker's backend ignore CORS, so access to the API is protected only by authentication and authorisation.
*is fine for public data without cookies, and with credentials the browser simply rejects it. But echoing anyOrigintogether withAllow-Credentials: trueis a real hole: any site a logged-in user opens can read API responses on their behalf, meaning personal data and CSRF tokens. The right way: an allowlist of specific origins with exact matching, andVary: Originso caches do not mix responses.Follow-up question: Why is a check like
origin.endsWith('example.com')in such an allowlist also vulnerable?- Course: Web application security
- Source: developer.mozilla.org
7. An SPA keeps a JWT with a one hour lifetime in
localStorage, and the "Log out" button just removes it from there. A tester copied the token before logging out, and after logout the API keeps accepting it for an hour. Is this a bug? What do you change?Answer
Yes, and it is built into JWT itself: the token carries signed claims (header, payload, signature), and the server checks the signature and
expwithout touching any store, so deleting it on the client does not invalidate it. Options: a short access token of 5 to 15 minutes plus a refresh token that the server stores and revokes on logout; a denylist of revokedjtivalues until theirexp, at which point validation is no longer fully stateless; or a plain server session if there is a single backend. The second problem islocalStorage: any script on the page can read it, so one XSS steals the token, which is why the refresh token is better kept in anHttpOnlycookie. And the payload is not encrypted, anyone can read it, so no secrets go there.Follow-up question: How does an HS256 signature differ from RS256, and when do you choose which?
- Course: Auth and security
- Knowledge base: JWT
- Source: rfc-editor.org
8. A pentest showed that the account settings page can be embedded in an
<iframe>on any site, with a "Claim your prize" button laid exactly over "Delete account". What is the attack called and what do you add to the server response? Which other security headers are worth adding in the same change?Answer
This is clickjacking: the user clicks on a transparent iframe of your site where they are logged in. Defence:
Content-Security-Policy: frame-ancestors 'self'(or'none'), andX-Frame-Options: DENYorSAMEORIGINfor old browsers; a cookie withSameSite=Laxalso helps, because it is not sent inside a cross-site iframe. The same change usually addsStrict-Transport-Security,X-Content-Type-Options: nosniff(the browser does not guess the type and will not run an uploaded file as a script) andReferrer-Policy: strict-origin-when-cross-origin, so paths with parameters do not go to third-party sites. A CSP for scripts is introduced separately and gradually, throughContent-Security-Policy-Report-Only, because it easily breaks pages.Follow-up question: A partner legitimately embeds your page on their own domain. How do you allow only them?
- Course: Web application security
- Source: owasp.org
Middle questions
1. Before a release the client asks you to "check the API for OWASP Top 10 compliance". You have two days and a REST API with 20 endpoints. Where do you start and what do you actually check?
Answer
The OWASP Top 10 is a ranking of risk categories for awareness and prioritisation, not a standard you can "comply with"; for verification there is OWASP ASVS, and for APIs a separate API Security Top 10. In two days I take what breaks most often: access control (A01, first place), meaning every endpoint called with another user's token and another role's token; injection wherever there is raw SQL or command building; authentication (login limits, token lifetime and validation). In parallel the automated part: a dependency scanner (
npm audit, Dependabot), a secret scan of the repository, a basic DAST run such as ZAP baseline, configuration (CORS, debug mode, stack traces in responses). The client gets a list of findings with risk and fix status, not the phrase "we comply with the Top 10".Follow-up question: Which category is first in the Top 10, and why do automated scanners catch it poorly?
- Course: Web application security
- Source: owasp.org
2. The site opens in the browser with a padlock, but a partner's Node.js service and
curlfail withunable to verify the first certificate. A colleague suggests settingNODE_TLS_REJECT_UNAUTHORIZED=0. What is actually wrong and how do you check it?Answer
Most often the server sends only the domain certificate without the certificate authority's intermediate certificate. Browsers hide this: they cache intermediates and can fetch a missing one from the AIA link, while Node.js, curl, Java and mobile clients build the chain only from what the server sent and never reach a trusted root. To check:
openssl s_client -connect example.com:443 -servername example.com -showcertsor SSL Labs will show a single certificate in the chain. The fix: point the server config atfullchain.peminstead ofcert.pem.NODE_TLS_REJECT_UNAUTHORIZED=0turns off certificate verification for the whole process and opens the way to MITM, so it is not a fix.Follow-up question: What else does a client check in a certificate besides the chain to a trusted root?
- Course: Web application security
- Source: developer.mozilla.org
3. Which items of OWASP API Security Top 10 2023 do you see most often in a backend API, and how does this list differ from the classic Top 10?
Answer
The most frequent: API1 BOLA, where an object is looked up by an id from the URL without an ownership check; API3 BOPLA, extra fields in the response or mass assignment in the request body; API5 BFLA, an admin function without a role check, often on another method or API version; API4 and API6, no limits and no protection of business flows from bots. The API list is shifted toward authorization and endpoint inventory rather than XSS or rendering, because an API has no browser UI.
Follow-up question: How do you find forgotten old versions and staging endpoints (API9) in time?
- Course: Web application security
- Source: owasp.org
4. A pentest found that when updating a profile a regular user became admin, and the response shows a password hash. What is this vulnerability and how do you fix it?
Answer
This is BOPLA: mass assignment on input and excessive fields on output. The controller copies the request body into an entity without a whitelist, and the client adds
role: "admin", and on the response the whole entity is returned. Fix: separate input and output DTOs listing only allowed fields, validation that rejects unknown properties, and explicit response construction instead of serializing the model. Fields that change privileges are allowed only on a dedicated admin endpoint.Follow-up question: Why is a role check on the endpoint not enough if the role can be changed through the profile?
- Course: Web application security
5. A user changed the id in the URL
/orders/123to/orders/124and saw someone else's order. What is this and how do you fix it systematically?Answer
This is IDOR, in OWASP API terms BOLA: the server checks that the user is logged in, but not that the object belongs to them. Fix: check the owner or permission on every object access, or better build it into the database query (
WHERE id = ? AND owner_id = ?) or a common access layer, so you do not rely on a developer's memory. Unpredictable UUIDs instead of sequential ids make enumeration harder but do not replace permission checks. For regressions, write tests that try other users' ids.Follow-up question: How do you check a large API for BOLA automatically?
- Course: Web application security
- Source: owasp.org
6. A colleague says an ORM protects against SQL injection. When is that not true?
Answer
An ORM protects only when values go in as parameters. If in a query builder or raw query a value is interpolated with a template string (
where(name = '${name}')), that is an ordinary injection. The same goes for column names and the direction inORDER BYthat come from the client: they cannot be passed as parameters, so they are checked against a list of allowed values. In Prisma,$queryRawUnsafeis dangerous, while the tagged$queryRawparameterizes interpolations automatically. Reviewing every raw query is mandatory.Follow-up question: How do you check code for SQL injection automatically?
- Course: Web application security
7. A login on Express and Mongoose: an attacker gets in as admin without knowing the password. What request body could he have sent?
Answer
This is NoSQL injection through operators. If the code passes the body straight into the query
User.findOne({ email, password }), the attacker sends JSON{ "email": "[email protected]", "password": { "$ne": null } }, and the condition becomes true for any password. Defense: validate the type of input fields (a string, not an object) with a schema such as zod or class-validator, do not compare passwords through a database query but fetch the user by email and verify the hash in code, and if needed sanitize keys containing$.Follow-up question: Why is it important for a JSON API to reject unknown and nested fields?
- Course: Web application security
8. A backend serves comments for an SPA. After a stored XSS incident, the frontend says it is the backend's problem and the backend says it is the frontend's. Who is right?
Answer
Responsibility is shared. The main defense is output escaping at the place of rendering, that is on the frontend: React escapes text by default, while
dangerouslySetInnerHTMLorinnerHTMLcreate a hole. The backend is responsible for validation, sanitizing the allowed HTML with a proven library if HTML is needed, the correctContent-Typeand security headers, CSP andHttpOnlycookies, so session theft is harder. One layer is not enough, you need defense in depth.Follow-up question: Why should you not write an HTML sanitizer yourself with regexes?
- Course: Web application security
- Source: cheatsheetseries.owasp.org
10. Design a Content-Security-Policy for a React admin panel. Why is
unsafe-inlinefor scripts dangerous?Answer
Start with
default-src 'self'and open up only what is needed:script-srcfor your own domain,connect-srcfor the API,img-src, andframe-ancestors 'none'against clickjacking.unsafe-inlineallows any inline script to run, which is exactly what an XSS injects, so CSP loses its point. Instead you use a nonce or hashes that the server generates for each response. First enableContent-Security-Policy-Report-Only, collect reports, then move to enforcement.Follow-up question: How does CSP get along with third-party analytics scripts?
- Course: Web application security
- Source: developer.mozilla.org
11. A user provides a webhook URL, the service sends a request to it and shows the response. What vulnerability is this and how do you close it?
Answer
This is SSRF: the server can be made to reach internal addresses such as
http://localhost, private networks or the cloud metadata address169.254.169.254, and hand back the result. Defense: allow onlyhttpsand an allow-list of hosts where possible; resolve DNS yourself and reject private, loopback and link-local addresses; do not follow redirects after the check; limit time and response size; keep such requests in an isolated network segment with no access to internal services. Do not show the response to the user raw.Follow-up question: Why is a blocklist by host string easy to bypass?
- Course: Web application security
- Source: cheatsheetseries.owasp.org
12. An endpoint accepts a zip, extracts the files and serves them by a link from the same domain. What are the risks?
Answer
Zip slip: names like
../../etc/xwrite files outside the target directory, so the path after normalization must stay within the folder. Zip bomb: a small archive expands into gigabytes, so you limit total size, file count and depth. Serving uploaded files from the main domain leads to stored XSS (HTML or SVG), so they are served from a separate domain or withContent-Disposition: attachmentandX-Content-Type-Options: nosniff. The file type is checked by content, not by extension, and uploaded files are not executed.Follow-up question: Why can an uploaded SVG be an XSS vector?
- Course: Web application security
- Source: cheatsheetseries.owasp.org
13. A service generates image previews by calling ImageMagick through
execwith a user-provided file name. What injections are there, and is escaping quotes enough?Answer
Command injection:
execstarts a shell, so a name likea.png; rm -rf /runs an extra command. There is also argument injection: a name starting with-is interpreted as an option of the utility. Quotes do not solve the problem. The right way: useexecFile/spawnwithout a shell and with an argument array, put--before file names, generate your own file names on disk instead of user-supplied ones, and better still call a library instead of a process. Run with minimal privileges in a restricted environment.Follow-up question: How is
execFilesafer thanexecin Node?- Course: Web application security
- Source: cheatsheetseries.owasp.org
14. How do you choose argon2id or bcrypt parameters for login, and what is a pepper?
Answer
Parameters are tuned so that one check takes about 100 to 500 ms on your hardware: argon2id with parameters from OWASP recommendations, or bcrypt with a cost of at least 10 to 12. They are raised over time and the password is rehashed on the next successful login. A pepper is a secret shared by the whole system, added to the password or hash and stored separately from the database, for example in a secrets manager. It helps when only the database leaked. A heavy hash also needs DoS protection: limits on login rate and concurrency.
Follow-up question: Why does bcrypt truncate long passwords and how is that worked around?
- Course: Auth and security
- Source: cheatsheetseries.owasp.org
15. By what paths do secrets leak from a service, and is it enough to delete
.envfrom the repo in the next commit?Answer
It is not enough: the file stays in git history, so the key is treated as compromised and rotated. Typical leak paths: git history, Docker image layers, environment variables in logs and in
docker inspect, error messages with a connection string, CI logs, artifacts and client bundles that got variables without a prefix check. Defense: secret scanners in pre-commit and CI, a secrets manager, least-privilege keys with a short lifetime, masking in logs, separate keys per environment.Follow-up question: How do you check that a secret did not end up in a client JS bundle?
- Course: Web application security
- Knowledge base: Terraform
16. TLS is terminated at Nginx, and the app listens on localhost behind it. What should you pay attention to in the configuration?
Answer
Allow only TLS 1.2 and 1.3 with modern ciphers, enable HSTS, an HTTP to HTTPS redirect and automatic certificate renewal (Let's Encrypt). The app must know the original request was secure: Nginx passes
X-Forwarded-ProtoandX-Forwarded-For, and the app trusts these headers only from its own proxy, otherwise a client can forge them. OtherwiseSecurecookies and absolute links will misbehave. The hop between Nginx and the app on the same host is protected by isolation, but across a separate network you need encryption.Follow-up question: Why is trusting
X-Forwarded-Fordangerous without proxy configuration?- Course: Web application security
- Knowledge base: nginx
- Source: developer.mozilla.org
17. You enabled
Strict-Transport-Security: max-age=63072000; includeSubDomains; preloadand submitted the domain to the preload list. The next day the internallegacy.example.com, which runs only over HTTP, opens for nobody. Why, how do you roll back, and how should it have been rolled out?Answer
HSTS tells the browser to use only HTTPS for the domain for
max-ageand does not let the user click through a certificate error, andincludeSubDomainsextends this to every subdomain, so the HTTP-onlylegacystopped opening. Rollback is slow: you can sendmax-age=0, but browsers that do not visit the main domain afterwards keep the old rule for up to two years, and the preload list is built into browsers, so removal stretches over months of releases. The right way: first move every subdomain to HTTPS, start with a smallmax-age(minutes, then a week, a month) withoutincludeSubDomains, and only then add it andpreload. In return HSTS closes the SSL stripping window on the first HTTP request, and with preload it protects even the first visit.Follow-up question: Which public Wi-Fi attack does HSTS prevent, and why is a redirect from HTTP to HTTPS not enough for that?
- Course: Web application security
- Source: developer.mozilla.org
18. In a multi-tenant SaaS on one database, customer A saw customer B's invoices. Where does the mistake usually hide and how do you make isolation reliable?
Answer
Typical holes: a query without a
tenant_idcondition, lookup by id without a tenant check, background jobs or cache without a tenant key, aggregations and exports. Relying on a developer to rememberWHERE tenant_idis unreliable. Isolation is built into the access layer (a mandatory filter in the repository or ORM scope), the tenant comes from the authenticated context rather than a request parameter, and at the database level you enable Row Level Security as the last line. Add tests with two tenants that check cross-tenant access.Follow-up question: Why must the cache key also contain the tenant identifier?
- Course: Auth and security
- Knowledge base: PostgreSQL
19. In code review the authentication middleware calls
jwt.decode(token)and takesuserIdfrom the payload, and another route callsjwt.verify(token, key)with no options at all. What is dangerous here and what else must the backend check besides the signature?Answer
jwt.decodeonly parses base64url and does not check the signature, so anyone can forge a payload with someone else'suserId.verifywithout options is weak too: the algorithm must be pinned with a list (algorithms: ['RS256']), otherwise old libraries acceptedalg: none, and swapping RS256 for HS256 turns the public key into an HMAC secret. Besides the signature you checkexpandnbf, plusissandaudso you do not accept a token issued for another service, and you do not trust akidorjkupointing to an arbitrary URL with keys. Tokens meant for something else, such as an id token, are not accepted as an access token; RFC 8725 collects all of this.Follow-up question: How do you rotate the signing key without logging every user out?
- Course: Auth and security
- Knowledge base: JWT
- Source: rfc-editor.org
20. Partners integrate with your API through keys. How do you design the key format, storage, verification and rotation?
Answer
The key is generated by a cryptographic generator, long enough, with a prefix that identifies the type and lets scanners find leaks. It is shown once, and the database stores only a hash (a fast SHA-256 is enough because the key has high entropy) and a short public prefix for lookup. For each key you set scopes and limits, an expiry and an owner. Rotation: two keys can be active at once so the client switches without downtime. Usage is logged and suspicious keys are revoked immediately.
Follow-up question: Why do API keys not need a slow argon2 like passwords do?
- Course: Auth and security
21. A reporting service pulls data from your API hourly without a user. Which OAuth2 flow do you use?
Answer
Client credentials: the service as a client authenticates to the authorization server with its
client_idand secret (or better a certificate or signed assertion) and receives a short-lived access token with the needed scopes. There is no user here, the token represents the service itself. The token is cached until it expires rather than requested on every call. The client secret is stored as a secret, rotated, and granted minimal scopes.Follow-up question: How does client credentials differ from authorization code?
- Course: Auth and security
- Knowledge base: OAuth 2.0, Keycloak
- Source: rfc-editor.org
22. The authorization code flow has
state,nonceandcode_verifier. What does each one protect against?Answer
statebinds the response to the request that this very user initiated and protects the redirect endpoint from CSRF.nonceis embedded in the id token and checked by the client, which protects against replay of the id token.code_verifierin PKCE proves that the code exchange is done by the same client that started the flow: an intercepted code without the verifier is useless. PKCE is now recommended for all clients, not only public ones.Follow-up question: Why is the implicit flow no longer recommended?
- Course: Auth and security
- Knowledge base: OAuth 2.0, OpenID Connect
- Source: rfc-editor.org
23. A user pressed 'Log out' in an app that signs in through Keycloak. What should happen on the client, in the backend and in the provider?
Answer
On the client you delete the local session and tokens from memory or cookies. In the provider you end the SSO session through the end-session endpoint (RP-initiated logout), otherwise the next login will pass without a password. Refresh tokens are revoked through the revocation endpoint. A JWT access token stays valid until
exp, so its lifetime is kept short, and for critical operations revocation is checked through introspection or a denylist. You can also use back-channel logout so the provider notifies all applications.Follow-up question: What is back-channel logout?
- Course: Auth and security
- Knowledge base: Keycloak, OpenID Connect
24. An API accepts tokens from a shared realm, and a pentest got into the API with an id token. Why is this a problem and how do you fix it?
Answer
An id token is meant for the client to learn who logged in, not for calling an API. Its
audis the client, not your API, so an API that checks only the signature andissaccepts a token issued for any application in the realm. Fix: the API checksaud(orazpand scope) against its own identifier, accepts only access tokens of the right type, and tells them apart by claims such astyp. Use a separate audience per resource server.Follow-up question: How does an access token differ from an id token in content and purpose?
- Course: Auth and security
- Knowledge base: OpenID Connect, Keycloak, JWT
25. The security team found tokens, passwords and password reset links in the logs. How do you fix this systematically?
Answer
Log selectively, not 'the whole request and response'. Set up masking at the logger level by a list of sensitive keys (
password,authorization,token,cookie) and never log the bodies of authentication requests. Reset links and tokens in URLs end up in proxy logs, so make them short-lived and single-use. Add tests that check no secrets appear in logs, and restrict access to the logs themselves and their retention. Whatever already got into logs is considered compromised and rotated.Follow-up question: Why are secrets in query parameters worse than secrets in headers?
- Course: Web application security
- Knowledge base: Grafana Loki, ELK Stack
26. Password reset emails a six-digit code valid for 15 minutes. The limit on the code check endpoint is 5 requests per minute per IP. A pentester resets the password of any account within an hour. How, and what do you fix?
Answer
There are only a million codes, and a per-IP limit is bypassed by rotating addresses through proxies or a botnet, so brute force from a few thousand IPs fits within the code's lifetime; on top of that the code can usually be reissued to start over. The limit belongs on the code and the account: after 5 failed attempts the code is voided, reissues per account are capped, and delays and CAPTCHA kick in on suspicion. Better still, instead of a short code send a link with a random single-use token of at least 128 bits and a short lifetime, storing only its hash in the database. The answer "if such an account exists, we sent an email" does not reveal which emails are registered, and permanent account lockout is avoided, because an attacker would use it to lock out other users.
Follow-up question: The same endpoint sends an SMS instead of an email. Which other attack appears and how do you limit it?
- Course: Auth and security
- Source: cheatsheetseries.owasp.org
27. After a phishing campaign several employees with SMS and TOTP 2FA turned on still lost their accounts: they entered the password and the code on a fake login page. Why did MFA not help and what would have?
Answer
Modern phishing works as a proxy between the victim and the real site (adversary in the middle, tools like Evilginx): it relays the password and the one-time code in real time and takes the session cookie, so SMS, TOTP and push are all bypassed. Passkeys and FIDO2 keys on WebAuthn resist this: the private key stays on the device and the signature is bound to the domain (RP ID), so a fake domain gets no valid response. Push without number matching is also open to prompt fatigue, and SMS to SIM swap. Account recovery and enrolment of a new factor need closing separately, because attackers often go there, and sessions are shortened or bound to the device.
Follow-up question: How would you roll out passkeys to existing users without breaking login for those who do not have one yet?
- Course: Auth and security
- Knowledge base: Passkeys
- Source: webauthn.guide
Senior questions
1. A colleague proposes removing CSRF tokens because browsers now default to
SameSite=Lax. When is he right and when not?Answer
Laxblocks the cookie on cross-site POSTs and subrequests, so the main class of attacks is closed. But there are limits: the cookie is still sent on top-level GET navigation, so state-changing GET endpoints remain vulnerable. Requests within the same site but across different origins, such as from a sibling subdomain, are not filtered by SameSite. Old browsers and third-party clients behave differently, and Chrome gives a two minute window for new cookies without an explicit attribute. So tokens or anOrigincheck remain a useful second layer.Follow-up question: How does a site differ from an origin?
- Course: Auth and security
2. Code resolves a domain and checks the IP is not private, then makes the request. Is that enough against SSRF?
Answer
No, because of DNS rebinding and TOCTOU. The attacker controls DNS: the first answer gives a public IP and passes the check, and at connection time the client resolves again and gets
127.0.0.1. Fix: resolve once and connect to exactly that verified IP, passing the originalHost, or check the address at the socket level, in a customlookupor through an outbound proxy. Also check every redirect anew and cover IPv6 variants and decimal or hexadecimal forms of addresses.Follow-up question: Why is an outbound proxy with an allow-list more reliable than a check in application code?
- Course: Web application security
3. After another service's database leak, your login received 2 million attempts from 40 thousand IPs, 1 to 3 attempts per account. What do you do?
Answer
This is credential stuffing: login and password pairs from someone else's leak. Per-IP limits are useless because the IPs are spread out. What helps: MFA or passkeys, checking passwords against lists of exposed ones (for example via the k-anonymity API of Have I Been Pwned), limits per account and by anomalies (new devices, bot behavior), CAPTCHA or proof-of-work when suspicious, and notifying users about a login from a new device. Do not reveal whether an account exists: identical responses and timing on failure.
Follow-up question: How does k-anonymity work in checking exposed passwords?
- Course: Auth and security
- Knowledge base: Passkeys
4. Compare RBAC, ABAC and ReBAC on the example of a document system: a user sees their own documents, their team's documents and shared ones.
Answer
RBAC grants rights by roles (
editor,admin): simple and clear, but roles multiply and rules about specific objects are hard to express. ABAC decides by attributes of the user, resource and context (department, document status, time): flexible, but rules are hard to audit. ReBAC derives access from a graph of relationships (owner, team member, a document in a folder that was shared), as in Google Drive or Zanzibar-like systems, and describes shared access naturally. In practice they are combined: roles for broad rights, relationships for objects, attributes for exceptions.Follow-up question: How does ReBAC answer the question 'who has access to this document'?
- Course: Auth and security
5. You enabled Row Level Security to isolate tenants. It works in tests, but in production under load clients occasionally see foreign data. What do you suspect?
Answer
Most likely the tenant is passed through a session setting (
SET app.tenant_id), and the connection pool returns a connection carrying the previous request's tenant. Solution:SET LOCALinside a transaction so the value resets when it ends, set at the start of each one. Other pitfalls: the table owner and superuser bypass RLS unlessFORCE ROW LEVEL SECURITYis set, and the application must not connect as the owner role. PgBouncer in transaction pooling mode needs exactly a per-transaction setting.Follow-up question: How do you debug an RLS policy when it silently hides rows?
- Knowledge base: PostgreSQL
- Source: postgresql.org
6. Where should an SPA keep tokens? A colleague stores access and refresh tokens in
localStoragebecauseHttpOnlycookies are 'inconvenient'.Answer
Anything in
localStoragecan be read by any script on the page, so one XSS exposes both tokens, including the long-lived refresh token. A more reliable pattern is BFF: a small backend on your domain performs the OAuth exchange, keeps the tokens on the server, and gives the browser only anHttpOnly,Secure,SameSitecookie session. Then tokens are inaccessible to JS, but you need CSRF protection. If a token must still be in the browser, keep it in memory, make it short-lived and rotate the refresh token.Follow-up question: What are the drawbacks of a BFF compared with tokens in the browser?
- Course: Auth and security
- Knowledge base: OAuth 2.0, JWT
- Source: datatracker.ietf.org
7. After introducing refresh token rotation with reuse detection, users with two tabs are massively logged out. Why?
Answer
With rotation each refresh token is single-use, and reuse of an old one is treated as theft and the whole token family is revoked. Two tabs refresh at the same time with the same refresh token, the second loses the race, and the system sees 'reuse'. Solution: coordination on the client (one tab refreshes, the others wait via a lock or
BroadcastChannel), and on the server a small grace window in which the previous token is still accepted, which gives idempotency on network retries. Also check that the new pair definitely reached the client.Follow-up question: What do you do with the token family on a real reuse?
- Course: Auth and security
- Knowledge base: OAuth 2.0, JWT
8. The billing service trusts the
X-User-Idheader set by the gateway. Through SSRF in another service an attacker called billing directly. What went wrong?Answer
The internal network was considered trusted, so billing accepted any
X-User-Idwithout checking the source. One SSRF made it possible to bypass the gateway and substitute someone else's identity. Fix: services verify a cryptographically proven identity, not a header. That means a signed token (the user's JWT passed along, or a service token), mTLS between services or network policies that admit only known services to billing. This is the zero trust idea: the network is not trust.Follow-up question: How do you pass a user's identity between services while keeping verification?
- Course: Auth and security
- Knowledge base: JWT, Kubernetes
9. Internal services talk over HTTP inside the cluster and pass one shared API key. Security demands mTLS. What does it give you compared to the key, what does it cost to operate, and how would you roll it out?
Answer
mTLS is TLS in which not only the server but also the client presents a certificate, so every service has a cryptographic identity and traffic is encrypted even inside a "trusted" network. Unlike a shared key, which leaks from any one service and opens all of them, a certificate is bound to a specific service, lives hours or days, and its private key is never sent in a request, so it does not end up in logs. The cost: an internal CA, issuing and automatically rotating short-lived certificates, expiry monitoring, harder debugging. That is why mTLS is usually handed to a service mesh (Istio, Linkerd) or SPIFFE/SPIRE, which make rotation transparent, and enabled gradually: permissive mode first, then strict. mTLS answers "who is calling", while what that service may do is still decided by authorisation.
Follow-up question: How do you avoid an outage caused by an expired internal certificate?
- Course: Auth and security
- Knowledge base: Kubernetes
- Source: spiffe.io
10.
npm auditshows 47 vulnerabilities, the team has ignored them for a long time, and the news is full of attacks through packages. What do you do?Answer
Do not drown in noise: prioritize by reachability and exploitability, because many vulnerabilities are in dev dependencies or in code that is never called. Pin versions through a lock file and reproducible installs (
npm ci), automate updates (Dependabot or Renovate) and scanning in CI. Against supply chain attacks it helps to vet new packages and maintainers, avoid arbitrarypostinstallscripts from unknown packages, keep dependencies minimal, and use an SBOM and artifact signatures. Publishing and CI tokens are protected, and secrets are kept out of the build environment.Follow-up question: How does typosquatting differ from dependency confusion?
- Course: Web application security
- Knowledge base: GitHub Actions
- Source: owasp.org
11. On Friday evening you learn that the JWT signing secret has been in a contractor's public GitHub repo for three days. What do you do?
Answer
Assume compromise: tokens can be forged. First containment: rotate the signing key, which invalidates all issued tokens (users log in again), with a transition period through
kidif needed. Then investigation: check logs for suspicious tokens, unusual permissions and actions that started in this period. Remove the secret from the repo but treat it as already copied. Notify those responsible and, if needed, users or a regulator. After that a postmortem: how the secret got out and how to prevent a repeat.Follow-up question: How do you rotate a JWT signing key without mass logout?
- Course: Auth and security
- Knowledge base: JWT
Train these questions
Study the cards, answer by text or voice and get an AI grade. Needs a signed in account.
Answer out loud and get graded
Here you get the questions with model answers. In the ShortLesson app you answer yourself, by text or voice, and AI grades the answer against the rubric and asks a follow-up, like a real interviewer.
The app is coming to the stores soon.
Other topics
- JavaScript interview questions and answers
- TypeScript interview questions and answers
- React interview questions and answers
- Frontend performance interview questions and answers
- Node.js interview questions and answers
- NestJS interview questions and answers
- HTTP interview questions and answers
- SQL interview questions and answers
- Databases interview questions and answers
- Git interview questions and answers
- Algorithms interview questions and answers
- System design interview questions and answers
- DevOps interview questions and answers
- Testing interview questions and answers