CORS middleware reflects Origin with Allow-Credentials, enabling cross-origin attacks (CWE-346)
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 6.5k
- Forks
- 787
- PR merge metrics
- No merged PRs in 30d
Description
Summary
The CORS middleware reflects the request's Origin header back as Access-Control-Allow-Origin when the configured allow_origin contains *, while simultaneously setting Access-Control-Allow-Credentials: true. This is a well-known CORS misconfiguration that allows any website to make authenticated cross-origin requests to the StackStorm API.
Affected File
st2common/st2common/middleware/cors.py (lines 65-69, 88, 91)
if origin:
if "*" in origins:
origin_allowed = origin # reflects whatever the browser sends
else:
origin_allowed = origin if origin in origins else list(origins)[0]
# ...
headers["Access-Control-Allow-Origin"] = origin_allowed
# ...
headers["Access-Control-Allow-Credentials"] = "true" # always set
Additionally, the middleware hardcodes localhost development origins that are always allowed:
# Default gulp development server WebUI URL
origins.add("http://127.0.0.1:3000")
# By default WebUI simple http server listens on 8080
origins.add("http://localhost:8080")
origins.add("http://127.0.0.1:8080")
Impact
When allow_origin contains *:
Any website can make authenticated, credential-bearing requests to the StackStorm API from a user's browser. If a StackStorm user visits a malicious page while logged in, the attacker can:
- Read API responses (execution results, datastore values, pack configurations)
- Trigger action executions
- Modify rules and workflows
- Exfiltrate API keys and tokens
This is because the combination of a reflected Access-Control-Allow-Origin and Access-Control-Allow-Credentials: true tells the browser to include cookies/auth headers and allow the response to be read by the requesting page.
Hardcoded localhost origins:
If an attacker can run a web server on localhost:3000 or localhost:8080 on a machine where a StackStorm user has an active session, they can exploit these hardcoded origins. These should not be present in production builds.
Recommended Fix
-
Never reflect the
Originheader whenAccess-Control-Allow-Credentialsistrue. If wildcard origin is configured, either:- Set
Access-Control-Allow-Origin: *and removeAccess-Control-Allow-Credentials(allows unauthenticated CORS only) - Or reject the configuration and log a warning
- Set
-
Remove hardcoded localhost origins from the default allowed list. These should only be present in development configurations.
-
Only set
Access-Control-Allow-Credentials: truewhen the origin is explicitly whitelisted (not wildcarded).
if origin and origin in origins:
headers["Access-Control-Allow-Origin"] = origin
headers["Access-Control-Allow-Credentials"] = "true"
elif "*" in origins:
headers["Access-Control-Allow-Origin"] = "*"
# Do NOT set Allow-Credentials with wildcard origin
References
- CWE-346: Origin Validation Error
- PortSwigger: Exploiting CORS Misconfigurations
- Discovered via manual code review
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading st2common/st2common/middleware/cors.py at the referenced lines 65-69, 88, and 91, and trace how configured origins become response headers. Verify that wildcard origins do not receive credentials, explicit allowlisted origins retain credentials, and hardcoded localhost origins are absent from production defaults.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- api, backend, security
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100