Sign inCreate account

The OWASP Top 10 in plain words

The OWASP Top 10 is a list of the ten most common and serious security risks in web applications, published by the Open Worldwide Application Security Project. xsec groups every check it runs under one of these categories. Here is what each one means, how an attacker would use it, how to fix it, and how far xsec can check it for you.

Recent vulnerabilities in the stacks you build on, and how to check yours →

How far xsec goes

xsec scans your site from outside, like a visitor who is not signed in, and never sends requests that could change your data. Some categories are almost fully visible that way; others are mostly hidden inside your systems. This is how much of each category xsec covers today.

Good
xsec checks most of what can be seen of this category from outside.
Partial
xsec checks some important parts; other parts need access xsec does not have.
Basic
xsec checks one or two signals only. Use other reviews for the rest.
Not tested
No xsec check runs here today, so a scan says nothing about this category.

Full or passive? A site whose ownership is not verified gets a passive scan: xsec sends only what a normal browser would, with no test payloads and no guessed paths. That leaves injection, SSRF, logging signals and error handling untested, and access control and misconfiguration only partly checked. Verify the site to run the full scan.

A01:2025

Broken Access Control

People can see or do things they should not be allowed to, or make the server fetch what they choose.

What it is
Access control decides who may see which data and who may do which action. It is broken when the app forgets to check, checks only in the browser, or can be tricked into skipping the check. Since 2025 this category also covers server-side request forgery (SSRF): a feature that fetches a URL can be told to call places the server should never reach.
Why it matters
A customer changes the number in /invoices/1041 to /invoices/1042 and reads someone else's invoice. Or an attacker gives a link-preview feature the cloud metadata address (169.254.169.254) and your server hands back cloud credentials.
How to fix it
Check permissions on the server for every request, deny by default, and never rely on hidden links or buttons. Keep private files out of the public web folder. For features that fetch URLs, allow only the hosts they need and block private and internal addresses after resolving the name.
How far xsec goesPartial

xsec checks the parts of access control that show from outside: exposed files, directory listings, public source maps, CORS rules, open redirects and signs of CSRF (login forms without a token, session cookies without SameSite, actions behind a plain link). For SSRF it puts a unique address it controls into the GET parameters and routes it finds (up to 60 requests per scan); if your server fetches it, xsec sees the call arrive. Whether one user can reach another user's data needs a signed-in test, which xsec does not do.

xsec checks
Cannot check from outside
  • Whether a user can open another user's records by changing an id in the URL (IDOR)
  • Whether normal users can reach admin pages or actions (role checks)
  • Anything behind a login
  • URLs sent in POST bodies, JSON APIs or headers (SSRF)
  • Whether your server can reach internal or cloud metadata addresses: xsec proves the fetch, it does not aim it inward

On a passive scan:PartialOnly CORS, the CSRF signs and the source maps the site's scripts point to are checked. Exposed files, directory listings, guessed source maps, open redirects and SSRF need probe requests, which a passive scan does not send.

Checks in this category

Exposed sensitive files a01.sensitive-file
What it is
A file that should never be public, such as .env, a .git folder or a database backup, can be downloaded from the site.
Why it matters
A public .env file often holds database passwords and API keys. With them, an attacker goes straight to your data without touching the website.
How to fix it
Delete the file from the web root, block dot-files and backup extensions in the web server, and rotate every secret the file contained.
Backup of a real file is downloadable a01.backup-of-route
What it is
A leftover copy of a file the site serves — made by an editor or a deploy, with a name like config.php.bak or app.js~ — can be downloaded. The server does not run the copy, so it returns the raw source instead of executing it.
Why it matters
The backup holds the same code and configuration as the real file, including database passwords and API keys, in plain text. An attacker guesses the backup next to a page they already see.
How to fix it
Delete the backup from the web root and stop deploying editor or copy files; block the backup suffixes (.bak, .old, ~, .swp) at the web server or proxy. Rotate any secret the file held.
Cross-site request forgery confirmed a01.csrf-confirmed
What it is
A forged POST — the form's own fields, no CSRF token, no session cookie, and an untrusted Origin — was accepted by the server. This check runs only in an intrusive (aggressive) scan the site owner opted into.
Why it matters
A page on another site can make a signed-in user's browser perform this action without their knowledge: transfer money, change an email, delete data. The missing token is not a guess here — the forged request went through.
How to fix it
Require a per-session CSRF token on every state-changing POST (or SameSite=strict/lax cookies with an Origin check), and reject any request whose token or Origin does not match.
CORS trusts any website a01.cors-reflects-origin
What it is
CORS rules tell browsers which other websites may read your responses. Here the server copies back whatever origin asks, so it trusts every site.
Why it matters
A user who is signed in to your app visits evil.example. That page silently calls your API with the user's cookies and reads the answers, such as their profile or invoices.
How to fix it
Answer Access-Control-Allow-Origin only for a fixed list of your own domains, and never combine a reflected origin with Access-Control-Allow-Credentials: true.
CORS trusts the "null" origin a01.cors-null-origin
What it is
The server allows requests from the special origin "null". Any site can produce that origin by using a sandboxed frame.
Why it matters
An attacker's page loads a sandboxed iframe, which sends origin "null", and reads your users' data just as if you had allowed every site.
How to fix it
Remove "null" from the allowed origins. Allow only your own named domains.
Open redirect a01.open-redirect
What it is
A link on your site, like /login?next=…, sends users to any address given in the URL, including other people's sites.
Why it matters
A phishing email links to yourbank.com/go?url=evil.example. The link looks trustworthy because it starts with your domain, then lands the victim on a fake login page.
How to fix it
Only redirect to relative paths or to an allow-list of your own domains; reject anything else.
Public JavaScript source map a01.source-map-exposed
What it is
A .map file next to the site's JavaScript is public. It turns the minified code back into the original source files, often with comments.
Why it matters
An attacker reads your front-end as your developers wrote it: internal API routes, feature flags, admin screens and any key someone forgot in the code.
How to fix it
Do not publish source maps to production (or restrict them by IP); upload them to your error tracker instead.
Server-side request forgery (SSRF) a10.ssrf
What it is
A parameter that takes a URL makes your server fetch an address chosen by the requester.
Why it matters
An attacker points it at internal services or the cloud metadata address and reads secrets your server can reach but the internet cannot.
How to fix it
Allow only the hosts the feature needs, block private and metadata addresses after DNS resolution, and do not return the fetched content as is.
Directory listing a05.directory-listing
What it is
Visiting a folder shows a list of every file in it.
Why it matters
An attacker browses the list and finds backups, logs or uploads that were never linked anywhere.
How to fix it
Turn off directory indexes in the web server (for example Options -Indexes on Apache, autoindex off on nginx).
Action triggered by a simple link a04.state-change-via-get
What it is
A URL such as /delete?id=7 or /logout changes something when it is just visited (GET), instead of requiring a form submission.
Why it matters
Another site can embed that URL in an image tag; a signed-in user who visits it performs the action without knowing (CSRF). Search engines and link previews can trigger it too.
How to fix it
Make actions that change data use POST (or PUT/DELETE) with a CSRF token; keep GET for reading only.
Login form without CSRF token a07.password-form-no-csrf
What it is
The login form has no anti-CSRF token, a hidden random value that proves the form came from your own site.
Why it matters
Another site can sign the victim into the attacker's account (login CSRF); whatever the victim then saves goes to the attacker.
How to fix it
Add a CSRF token to the form (most frameworks do it for you) or use SameSite cookies.

OWASP's full write-up of A01 →

A02:2025

Security Misconfiguration

Servers and frameworks run with unsafe settings.

What it is
Servers, frameworks and browsers have many security settings. Misconfiguration means a protective setting is off, a debug feature is left on, or the default configuration was never hardened.
Why it matters
A production server shows a detailed error page with file paths and library versions, which tells an attacker exactly which known exploit to try. Or a missing header lets another site load yours in an invisible frame and trick users into clicking.
How to fix it
Use a hardened, repeatable configuration for every environment, turn off debug output and directory listings in production, and send the standard security headers (CSP, X-Frame-Options or frame-ancestors, nosniff, Referrer-Policy).
How far xsec goesGood

xsec checks the configuration you can see in HTTP answers: security headers and CSP, version banners, TRACE, and the HttpOnly and Secure flags of cookies.

xsec checks
Cannot check from outside
  • Server, cloud and database settings that never show in an HTTP answer
  • Default accounts and admin consoles on other ports

On a passive scan:PartialHeaders and cookie flags only. TRACE needs a probe request, which a passive scan does not send.

Checks in this category

No Content-Security-Policy a05.missing-csp
What it is
Content-Security-Policy (CSP) is a header that tells the browser which scripts may run on your page. There is none.
Why it matters
If an XSS bug slips in, nothing stops the injected script from running and sending your users' data elsewhere.
How to fix it
Start with a policy such as default-src 'self' and add the sources you really use; try it in report-only mode first.
Weak Content-Security-Policy a05.weak-csp
What it is
A CSP exists but allows inline scripts ('unsafe-inline') or scripts from anywhere, which cancels most of its protection.
Why it matters
An attacker who finds an XSS bug can still run code, because the policy allows exactly the kind of script they inject.
How to fix it
Remove 'unsafe-inline' and wildcards from script-src; use nonces or hashes for the inline scripts you need.
Page can be framed (clickjacking) a05.missing-frame-protection
What it is
Nothing stops another website from loading your page inside an invisible frame.
Why it matters
An attacker shows a game with a "Click here" button placed exactly over your hidden "Delete account" or "Transfer" button (clickjacking).
How to fix it
Send Content-Security-Policy: frame-ancestors 'self' (or X-Frame-Options: DENY).
Missing nosniff a05.missing-nosniff
What it is
Without X-Content-Type-Options: nosniff, browsers may guess a file's type and run it as a script even if it was served as something else.
Why it matters
A user uploads a file that looks like an image but contains JavaScript; an old browser guesses it is a script and runs it.
How to fix it
Send X-Content-Type-Options: nosniff on every response.
No Referrer-Policy a05.missing-referrer-policy
What it is
Without a Referrer-Policy, the full URL of your page can be sent to other sites when users follow a link.
Why it matters
URLs sometimes contain tokens or personal data (a reset link, a search term) that end up in a third party's logs.
How to fix it
Send Referrer-Policy: strict-origin-when-cross-origin (or stricter).
Software version disclosed a05.version-disclosure
What it is
Response headers reveal the exact server or framework version, for example Server: Apache/2.4.29.
Why it matters
An attacker looks up that version, finds its known vulnerabilities and goes straight to a matching exploit.
How to fix it
Hide version numbers in Server and X-Powered-By headers, and keep the software up to date anyway.
HTTP TRACE enabled a05.trace-enabled
What it is
The server answers the TRACE method, which echoes the request back, headers included.
Why it matters
Combined with other bugs, TRACE has been used to read cookies that should be hidden from scripts (cross-site tracing). It has no use in production.
How to fix it
Disable TRACE in the web server or load balancer (for example TraceEnable off on Apache).
Cookie without Secure a02.cookie-without-secure
What it is
A cookie is set without the Secure flag, so the browser may also send it over plain HTTP.
Why it matters
If the browser ever makes one HTTP request to your domain, an eavesdropper can capture the cookie, and with a session cookie, the user's account.
How to fix it
Add the Secure attribute to every cookie, especially session cookies.

OWASP's full write-up of A02 →

A03:2025

Software Supply Chain Failures

The site is built from parts with known holes or from sources nobody checks.

What it is
Almost every app is built on third-party libraries, frameworks, build tools and services. This category covers all of it: components with published security holes, and the way they reach your site (package registries, build pipelines, CDNs). When one link in that chain is weak or compromised, every site that uses it is exposed.
Why it matters
A site still loads jQuery 1.x. Its known XSS bugs are documented online, so an attacker does not need to find a new flaw, only to reuse a published one.
How to fix it
Keep a list of the components you use (an SBOM), update them regularly, remove the ones you do not need, use a dependency scanner (SCA) in your build, and protect the pipeline that builds and ships your code.
How far xsec goesPartial

xsec recognizes outdated front-end JavaScript libraries loaded by your pages, and lists the AI features it sees (and, on a full scan, published agent cards) as inventory. Server-side dependencies are invisible from outside.

xsec checks
Cannot check from outside
  • Server-side frameworks and packages (npm, pip, Maven, Composer…): use an SCA tool in your build
  • Operating system and server software patch level
  • Libraries bundled without a version in the file name
  • Your build and deployment pipeline (CI/CD) and package registries

On a passive scan:PartialSame as a full scan: library versions come from the pages a browser loads.

Checks in this category

Outdated JavaScript library a06.outdated-library
What it is
A page loads a front-end library version with publicly known security holes or that is no longer maintained.
Why it matters
The attack is already written up online; an attacker only has to find a page that uses the vulnerable feature.
How to fix it
Update the library to a supported version, or remove it if it is no longer needed.
AI feature detected a03.ai-surface
What it is
The site shows an AI feature from outside: an AI chat widget, an AI library in its code, a call to an AI provider's API or a route named like an AI endpoint. This is inventory, not a problem.
Why it matters
AI features bring their own risks: leaked provider keys, chat endpoints anyone can use to run up your bill, model answers rendered as HTML, agents with too much access. Knowing where they are is the first step.
How to fix it
Nothing to fix here. For each AI feature: keep provider keys on the server, require sign-in and per-user rate limits on chat endpoints, escape model output before showing it, and give agents only the tools and data they need.
Agent card published a03.agent-card-exposed
What it is
The site publishes a card or manifest for an AI agent at a well-known address (an A2A agent card, an AI plugin manifest or an MCP discovery document). It tells other agents what yours can do and where to reach it. This is inventory, not a problem.
Why it matters
Anyone can read it, attackers included: it is a map of what the agent can be asked to do. A card that lists more skills than you meant to offer, or that points to an endpoint without sign-in, shows them where to start.
How to fix it
Nothing to fix if it is meant to be public. Check that it lists only the skills or tools you mean to offer, that it says how clients sign in, and that the endpoint it points to really asks for that.

OWASP's full write-up of A03 →

A04:2025

Cryptographic Failures

Data travels or is stored without proper encryption.

What it is
Sensitive data (passwords, personal data, payment details, session cookies) must be encrypted on the way and at rest. This category covers missing or weak encryption, like a site that still works over plain HTTP.
Why it matters
On a café's public Wi-Fi, someone on the same network reads the traffic of a site served over HTTP and copies a user's session cookie, which lets them act as that user.
How to fix it
Serve everything over HTTPS with a valid certificate, redirect HTTP to HTTPS, turn on HSTS and mark cookies Secure. Use modern, well-known encryption for stored data and never invent your own.
How far xsec goesGood

Encryption in transit is fully visible from outside, and xsec checks it thoroughly: certificate, HTTPS redirect, HSTS, mixed content, forms over HTTP and passwords sent over HTTP.

xsec checks
Cannot check from outside
  • How data is stored on your servers (database encryption, password hashing)
  • Encryption between your own internal services

On a passive scan:GoodSame as a full scan: these checks only read what a browser sees.

Checks in this category

No HTTPS a02.no-https
What it is
The site does not answer over HTTPS, so everything travels unencrypted.
Why it matters
Anyone on the same Wi-Fi or along the network path can read and change pages, passwords and cookies.
How to fix it
Get a free certificate (for example from Let's Encrypt) and serve the whole site over HTTPS.
HTTP not redirected to HTTPS a02.http-not-redirected
What it is
The plain http:// version of the site still works instead of sending visitors to https://.
Why it matters
Users who type the address without https:// get the unencrypted site, and an attacker on their network can intercept that first visit.
How to fix it
Redirect every http:// request to the same https:// address with a 301 and turn on HSTS.
Untrusted certificate a02.invalid-certificate
What it is
The HTTPS certificate is expired, self-signed or issued for another name, so browsers cannot trust it.
Why it matters
Users learn to click through the warning, and then they cannot tell your site from an attacker's fake one.
How to fix it
Install a valid certificate for the exact host name and renew it automatically.
No HSTS a02.missing-hsts
What it is
The Strict-Transport-Security header tells browsers to always use HTTPS for your site. It is missing.
Why it matters
An attacker on public Wi-Fi can downgrade a visitor's first request to HTTP (SSL stripping) and read everything that follows.
How to fix it
Send Strict-Transport-Security: max-age=31536000; includeSubDomains on HTTPS responses.
HSTS too short a02.weak-hsts
What it is
HSTS is on, but its max-age is under 180 days, so browsers forget it quickly.
Why it matters
A visitor who has not come back for a while is again open to the HTTP downgrade that HSTS is meant to block.
How to fix it
Raise max-age to at least 15552000 (180 days); one year (31536000) is common.
Mixed content a02.mixed-content
What it is
An HTTPS page loads scripts or styles over plain HTTP.
Why it matters
An attacker on the network replaces that HTTP script with their own, which then runs inside your secure page.
How to fix it
Load every resource over https:// (or a relative URL) and add a CSP with upgrade-insecure-requests.
Form sends data over HTTP a02.form-posts-over-http
What it is
A form on an HTTPS page submits its data to an http:// address.
Why it matters
The page looks secure, but whatever the user types (contact details, payment data) is sent in clear text.
How to fix it
Point the form's action to an https:// address or a relative path.
Password sent over HTTP a07.login-over-http
What it is
A login form sends the username and password unencrypted.
Why it matters
Anyone on the same network reads the password as it is typed, and people often reuse that password elsewhere.
How to fix it
Serve the login page and its form target only over HTTPS.

OWASP's full write-up of A04 →

A05:2025

Injection

User input is run as code or as part of a database query.

What it is
Injection happens when text typed by a user reaches a database, a browser or a command line and is treated as instructions instead of plain data. SQL injection and cross-site scripting (XSS) are the best-known kinds.
Why it matters
An attacker types ' OR '1'='1 into a search box and the database returns every customer. Or they send a victim a link whose URL contains a script; when the victim opens it, the script runs on your site with the victim's session.
How to fix it
Use parameterized queries (prepared statements) for every database call, escape output for the place it lands (HTML, JavaScript, URL), and validate input against what you expect.
How far xsec goesPartial

xsec tests reflected XSS and SQL injection (by the database errors it causes) on URL parameters and GET forms. Other kinds of injection and other entry points are not tested.

xsec checks
Cannot check from outside
  • POST forms (xsec never submits them, to avoid changing your data)
  • Stored and DOM-based XSS
  • Blind SQL injection that shows no error
  • Pages behind a login, and other injection kinds (command, LDAP, template)

On a passive scan:Not testedInjection needs test payloads, which a passive scan does not send.

Checks in this category

Admin panel or console reachable a01.admin-panel-exposed
What it is
A management console or API explorer — a framework admin, an actuator, a database or queue console, a Swagger page — answers an anonymous request from the internet.
Why it matters
A console open to everyone is a direct way in: it exposes configuration, lets an attacker map the API, and often offers actions that should need an administrator.
How to fix it
Require authentication on the panel, or block it at the proxy so only an internal network reaches it. Turn off API explorers and actuators in production.
GraphQL introspection enabled a05.graphql-introspection
What it is
The GraphQL endpoint answers introspection queries, so anyone can download its full schema: every type, field and mutation the API exposes.
Why it matters
An attacker reads the whole API surface at once — hidden mutations, admin fields, internal object shapes — which turns probing your API into reading a map of it.
How to fix it
Disable introspection in production (for example `introspection: false` in Apollo Server), and require authentication on the GraphQL endpoint.
Reflected cross-site scripting (XSS) a03.reflected-xss
What it is
Text from the URL is put into the page without escaping, so a script placed in a link runs on your site.
Why it matters
An attacker sends a victim a crafted link. When it opens, the script runs as your site: it can read what the user sees, act on their behalf or show a fake login form.
How to fix it
Escape all user input for where it is placed (HTML, attribute, JavaScript), use your framework's auto-escaping, and add a strict Content-Security-Policy.
SQL injection a03.sql-injection
What it is
A value from the request broke the database query and a database error came back, which shows the input reaches SQL without protection.
Why it matters
With the same flaw, an attacker can read, change or delete any data in the database, for example dumping the whole users table.
How to fix it
Use parameterized queries or an ORM for every query, never build SQL by joining strings, and hide database errors from users.

OWASP's full write-up of A05 →

A06:2025

Insecure Design

The feature itself was planned without security in mind.

What it is
Some flaws are not coding mistakes but design mistakes: a feature that works exactly as built, yet was built in a way that can be abused. No patch fixes it; the flow has to change.
Why it matters
A password-reset flow that asks only for an email and a 4-digit code with unlimited tries: an attacker simply tries all 10,000 codes and takes over the account.
How to fix it
Think about abuse while designing (threat modeling): limit attempts, require confirmation for risky actions, and make actions that change data use POST with CSRF protection, never a plain link.
How far xsec goesBasic

Design flaws are mostly invisible from outside. xsec checks one signal only: whether a login's password field tells the browser how to handle the password. Without a visible login form, nothing runs here.

xsec checks
Cannot check from outside
  • Business logic abuse (prices, limits, workflows)
  • Whether your threat model and security requirements exist
  • Account recovery and other flows that need a signed-in user

On a passive scan:BasicSame as a full scan: the signal comes from pages a browser sees.

Checks in this category

Password field without autocomplete hint a07.password-autocomplete
What it is
The password field has no autocomplete="current-password" or "new-password" hint.
Why it matters
Password managers work less reliably, which pushes users toward short, reused passwords.
How to fix it
Add autocomplete="current-password" on login and autocomplete="new-password" on sign-up and reset forms.

OWASP's full write-up of A06 →

A07:2025

Authentication Failures

Logins and sessions can be guessed, stolen or reused.

What it is
This covers everything about proving who a user is and keeping them signed in: login forms, passwords, session cookies and multi-factor authentication.
Why it matters
A login form posts passwords over plain HTTP, or a session cookie can be read by JavaScript. One XSS bug on any page then lets an attacker steal the cookie and sign in as the victim without knowing the password.
How to fix it
Serve login only over HTTPS, mark session cookies HttpOnly, Secure and SameSite, protect forms against CSRF, offer multi-factor authentication and limit failed login attempts.
How far xsec goesPartial

When the site has a login form, xsec checks whether it shows any defense against automated attempts (CAPTCHA, multi-factor). On every site, it looks for private keys and direct calls to AI providers in the pages and scripts a browser downloads. On a full scan it also asks the usual MCP and AI model API addresses whether they answer without credentials (GET only: it never sends a prompt or lists an MCP server's tools). Passwords over HTTP, CSRF and cookie flags are counted under A04, A01 and A02, where OWASP 2025 puts them.

xsec checks
Cannot check from outside
  • Weak passwords or brute-force protection (xsec never guesses passwords)
  • Multi-factor authentication, session expiry and logout
  • Password reset and sign-up flows

On a passive scan:GoodSame as a full scan, except open MCP and AI model APIs: finding them means guessing addresses, which a passive scan does not do.

Checks in this category

Login without anti-automation a04.no-login-hardening-signal
What it is
The login page shows no sign of CAPTCHA, multi-factor authentication or similar protection against automated attempts.
Why it matters
Attackers run lists of leaked passwords against your login (credential stuffing). Without limits, some accounts will fall.
How to fix it
Limit and slow down failed attempts, offer or require MFA, and add a challenge after repeated failures.
Secret key in the browser's code a07.secret-in-js
What it is
A private key (a payment, cloud, code-hosting, AI provider or database admin key) is inside a page or script that every visitor downloads.
Why it matters
Anyone who opens the browser's developer tools can copy the key and use it as you: charge cards, read the database without its access rules, or run up a cloud bill.
How to fix it
Revoke and rotate the key now, then move the call that needs it to your server. The browser should only hold public keys.
Browser calls an AI provider directly a07.llm-api-from-browser
What it is
The site's own code calls an AI provider's API (OpenAI, Anthropic, Gemini and others) from the visitor's browser, with a key it carries or with the provider's SDK set to run in the browser.
Why it matters
The key travels to every visitor. Anyone can copy it and run prompts on your account until the quota or the bill runs out, or use it to read what your other AI apps can.
How to fix it
Make the call from your server, behind your own sign-in and per-user rate limits, and keep the key there. Revoke and rotate a key that was in the browser's code, and set a spending limit with the provider.
MCP server open to anyone a07.mcp-endpoint-open
What it is
An MCP server (the protocol AI assistants use to call tools) answers on the public site without asking for credentials. xsec only knocked on the door: listing or calling its tools needs a POST, which a scan never sends.
Why it matters
An MCP server's tools are actions: read the database, send email, open tickets, run code. Anyone who connects an assistant to it can call them as if they were your app, and nobody has to sign in first.
How to fix it
Require sign-in on every request to the MCP server: OAuth as the MCP authorization spec describes, or at least a secret token. If only your own systems use it, keep it on a private network instead of the public site. Add rate limits and give each tool only the access it needs.
AI model API open to anyone a07.llm-endpoint-unauthenticated
What it is
An API that runs AI models (OpenAI-compatible, such as vLLM or LiteLLM, or Ollama) lists its models to anyone, without an API key. xsec did not send a prompt: that needs a POST, which a scan never sends.
Why it matters
If it lists models without a key, it usually answers prompts without one too. Strangers can then use your GPUs or your provider account for free, until the bill or the quota runs out.
How to fix it
Require an API key or the user's session on every route of the model API, keep it off the public site if only your servers call it, and set per-key rate limits and a spending cap.

OWASP's full write-up of A07 →

A08:2025

Software or Data Integrity Failures

Code or data is trusted without checking it was not tampered with.

What it is
An app trusts code or data from somewhere else (a CDN, an update server, a plugin, a serialized object) without verifying that nobody changed it on the way.
Why it matters
Your pages load a script from a third-party CDN. If that CDN is hacked, the attacker changes the script and it runs on your site for every visitor, for example to copy card numbers from the checkout form.
How to fix it
Add Subresource Integrity (an integrity="sha384-…" attribute) to scripts and styles from other domains, or host them yourself. Sign your builds and updates, and do not deserialize untrusted data.
How far xsec goesBasic

xsec checks one visible integrity control: whether scripts and styles from other domains carry a Subresource Integrity hash.

xsec checks
Cannot check from outside
  • Your build and deployment pipeline (CI/CD) security
  • Signed updates and plugins
  • Unsafe deserialization of untrusted data

On a passive scan:BasicSame as a full scan.

Checks in this category

Third-party script without integrity check a08.no-sri
What it is
A script or stylesheet from another domain is loaded without Subresource Integrity, a hash that lets the browser refuse a modified file.
Why it matters
If the CDN or third party is compromised, the altered script runs on your site for every visitor, for example to steal payment details.
How to fix it
Add integrity="sha384-…" and crossorigin="anonymous" to the tag, or host the file yourself.

OWASP's full write-up of A08 →

A09:2025

Security Logging and Alerting Failures

Attacks happen and nobody notices.

What it is
Logging and monitoring are how you find out you are being attacked. Without them, a breach can go unnoticed for months. Monitoring tools themselves must also not be open to the internet.
Why it matters
An attacker tries thousands of passwords over a weekend. Nothing alerts anyone, so the account is taken over before Monday. Or an internal dashboard like Grafana is left public and shows the attacker your infrastructure.
How to fix it
Log logins, failures and sensitive actions, send alerts on unusual patterns, rate-limit requests, and keep monitoring dashboards behind a VPN or a login.
How far xsec goesPartial

Logging happens inside your systems, so xsec only sees outside signals: monitoring tools left public, and whether repeated attack-like requests get slowed down or blocked.

xsec checks
Cannot check from outside
  • Whether you log logins, failures and sensitive actions
  • Whether anyone gets alerted, and how fast
  • Log retention and protection

On a passive scan:Not testedBoth signals need probe requests, which a passive scan does not send.

Checks in this category

Monitoring tool exposed a09.exposed-monitoring
What it is
A monitoring or admin tool (such as Grafana, Kibana, Prometheus or Spring Actuator) answers to anyone on the internet.
Why it matters
It can leak internal hosts, metrics, logs or configuration, and some of these tools allow actions or have known exploits.
How to fix it
Put monitoring tools behind a VPN, an internal network or a login, and never on the public site.
No visible rate limiting a09.no-rate-limiting-signal
What it is
Repeated requests carrying obvious attack patterns were all answered normally: nothing slowed them down or blocked them (no 429 or 403). This is a hint from outside, not a verdict on your logging.
Why it matters
Without limits, attackers can try passwords or scrape data at full speed, and nobody is alerted.
How to fix it
Rate-limit by IP and by account (a WAF or reverse proxy can help), and alert on spikes of failures.

OWASP's full write-up of A09 →

A10:2025

Mishandling of Exceptional Conditions

When something goes wrong, the app leaks details, crashes or fails open.

What it is
Every app meets errors: a missing value, a database that times out, a request it did not expect. This category is about handling them safely: catch errors where they happen, show users a plain message, log the details privately, and when in doubt, deny (fail closed) instead of letting the request through.
Why it matters
A malformed request makes a production server show a stack trace with file paths, library versions and a piece of the SQL query. An attacker uses those details to aim an injection attack. Or an authorization service times out and the app, failing open, lets the request through.
How to fix it
Use one error handler that returns a generic message and logs the details server-side, turn off debug pages in production, roll back half-done work when something fails, and make security checks deny by default when they cannot decide.
How far xsec goesBasic

xsec asks for a page that does not exist and sends malformed values to a few parameters, then looks for stack traces and debug pages in the answers. How the app behaves under other failures is not visible from outside.

xsec checks
Cannot check from outside
  • Whether security checks fail closed when a dependency is down
  • Resource leaks and half-finished transactions after an error
  • Errors in pages behind a login or in POST requests

On a passive scan:Not testedMalformed requests are probes, which a passive scan does not send.

Checks in this category

Detailed error pages a05.verbose-errors
What it is
Error pages show stack traces, file paths or framework details meant for developers.
Why it matters
They reveal how the app is built and which libraries it uses, which makes finding an attack much faster.
How to fix it
Turn off debug mode in production and show a generic error page; keep the details in your server logs.

OWASP's full write-up of A10 →

What "tested", "partial" and "not tested" mean

Every scan report has a coverage table. It tells you how much of each category the scan could actually check, so that a clean result is never mistaken for a guarantee.

tested
Every check xsec has for this category ran against your site. Those checks may still cover only part of the category: see how far xsec goes on the Learn page.
partial
Some checks ran, but part of the category could not be tested from outside or on this site. Zero findings here does not mean the category is clean.
not tested
No check in this category could run, so the scan says nothing about it, good or bad.

Why would a category not be tested?

← back to xsec