CWE-862, Missing Authorization, is exactly what it says. The product does not perform an authorization check when an actor tries to access a resource or perform an action. Login may work fine. The question "is this user allowed to do this?" simply never gets asked.
It hits any application with more than one user or role: web apps, REST and GraphQL APIs, admin consoles, plugins, workflow tools. It is easy to confuse with its sibling CWE-863, Incorrect Authorization, where a check exists but is wrong. Here the check is absent.
How it happens
Authentication proves who you are. Authorization decides what you may do. Teams often build the first carefully and apply the second unevenly: protected pages but unprotected API calls behind them, a new endpoint added without the middleware, a plugin function that never checks the user's capability.
The observed CVEs in MITRE's record are a good tour:
- CVE-2026-32228 (details): a workflow management product did not check authorization for running a workflow, so UI and API users could trigger workflow objects they had no access to.
- CVE-2024-6845: a chatbot WordPress plugin did not perform authorization on a REST endpoint, allowing retrieval of an API key.
- CVE-2025-2224: an AI-enabled WordPress plugin had a missing capability check on a function, allowing the public status of posts to be changed.
- CVE-2022-24730: a Go-based continuous deployment product did not check that a user had certain privileges to update or create an app, allowing adversaries to read sensitive repository information.
Notice that two involve AI features. New feature types still get shipped with the same old gap.
A minimal example of the pattern:
# Vulnerable: any logged-in user can delete any invoice
@app.route("/invoices/<int:invoice_id>", methods=["DELETE"])
@login_required
def delete_invoice(invoice_id):
Invoice.query.filter_by(id=invoice_id).delete()
return "", 204
The route checks that someone is logged in. It never checks that this person owns the invoice or holds a role that may delete it.
# Fixed: enforce ownership or role on the server
@app.route("/invoices/<int:invoice_id>", methods=["DELETE"])
@login_required
def delete_invoice(invoice_id):
invoice = Invoice.query.get_or_404(invoice_id)
if invoice.owner_id != current_user.id and not current_user.has_role("billing_admin"):
abort(403)
db.session.delete(invoice)
db.session.commit()
return "", 204
What an attacker gains
MITRE lists four kinds of impact:
- Confidentiality: reading data directly from an unrestricted store, or through privileged functionality that is not protected.
- Integrity: modifying data the same way.
- Access control: gaining privileges by reading or modifying critical data, or by reaching privileged functions.
- Availability: consuming CPU, memory or other resources through unauthorized access until the service degrades.
How to find it
MITRE rates the detection options differently, and the differences are useful:
- Automated static analysis can spot common authorization idioms and related config, such as .htaccess files or use of known authorization libraries. It has difficulty with custom schemes, and cannot tell whether a custom scheme is bypassable. MITRE rates its effectiveness as limited.
- Automated dynamic analysis may find many or all interfaces that do not require authorization, but a person must decide whether the missing check violates business logic.
- Manual analysis, such as penetration testing, threat modeling and interactive tools that let a tester record and modify a live session, covers business rules that tools cannot see.
A cheap routine check: build a table of every route and function with the role required, then look for blanks. Test each endpoint with no session, with a low privilege session and with another user's identifiers.
How to fix it
The MITRE mitigations, in plain steps:
- Divide the product into anonymous, normal, privileged and administrative areas. Map roles to data and functions, and use role based access control (RBAC) at the boundaries. MITRE cautions this will not stop horizontal attacks, where a user attacks others with the same role, so add object level checks too.
- Make access control checks that reflect business logic. A database may restrict medical records to one database user, but each record may only be meant for the patient and their doctor.
- Use a vetted library or framework that makes the weakness easier to avoid, such as an established authorization framework, instead of hand written checks.
- For web applications, enforce access control on the server for every page. Users must not reach unauthorized functionality by requesting a page directly. Sensitive pages should not be cached and should require an active, authenticated session token tied to a user with the needed permissions.
- Use the access control features of the operating system and server environment, and define access control lists with a default deny policy.
Default deny is the idea to take away. If a new route has no rule, it should be closed until someone writes one.
Try it yourself
The API security scan demo shows how an automated scan finds endpoints that answer without credentials.
Click through it at your own pace, or open it full screen.
Quick check
What is the difference between CWE-862 and CWE-863?
In 862 the authorization check is missing. In 863 a check exists but is performed incorrectly.
Does RBAC alone solve this?
No. MITRE notes RBAC may not protect against horizontal attacks between users of the same role, so you also need checks tied to the specific resource.
Can a scanner find all of it?
Tools find unprotected interfaces well, but a human has to judge whether a missing check breaks business rules.