I bypassed AWS API Gateway auth with a trailing slash. Got $12K bounty. – GuptaLog
Skip to content
GuptaLog
I was poking at a fintech’s mobile API and noticed something that made no sense. GET /v1/accounts returned 401. GET /v1/accounts/ returned 200 with full account data. One character. Completely different security posture.
What I was looking at
The API ran on AWS HTTP API — the newer, cheaper alternative to REST API. Lambda authorizer checked a JWT against Cognito, returned an IAM policy. Standard.
Routes in OpenAPI:
The authorizer ran on every request. But HTTP API makes two decisions: does this route exist, and does the authorizer allow it? Those two layers didn’t agree on what a “match” meant.
The weird results
I ran ffuf on the path. The results were… inconsistent.
RequestResponseGET /v1/accounts401 UnauthorizedGET /v1/accounts/200 OK + full dataGET /v1/accounts//200 OKGET /v1/accounts?foo=bar401 UnauthorizedGET /v1/accounts%2f404 Not Found
The pattern: any path that sort-of matched a route prefix triggered the authorizer, then fell through to the integration without re-checking auth.
HTTP API does greedy path matching by default. /v1/accounts/ matched /v1/accounts as a prefix. The authorizer ran and returned Allow. Then the integration executed — but the integration mapping was fuzzy. The path got rewritten, the auth context got dropped, and suddenly I was inside without a valid JWT.
How the bypass actually worked
I traced it carefully. The $default route in HTTP API is a catch-all. The fintech had set it to return 404. But they’d also attached a mock integration for health checks at some point. That mock didn’t check auth — just returned {"status": "ok"}.
But /v1/accounts/ wasn’t hitting the mock. It was hitting the real backend. API Gateway’s greedy match rewrote the trailing-slash path, stripped the slash, and forwarded to the /v1/accounts integration. The auth check happened on the original path. The integration ran on the rewritten path. The rewrite dropped the auth context.
I confirmed it with a custom header. The authorizer sets context.authorizer.userId. The integration reads it. When I hit /v1/accounts/, the integration received userId: undefined. The integration didn’t validate userId. It just returned all accounts for the API key — which wasn’t even required here because auth was supposed to be the JWT.
The real damage
Same bypass worked on POST /v1/transfers/. I could initiate wire transfers without a valid JWT.
The backend checked that fromAccount belonged to the user. But userId was undefined, so it defaulted to a system account. I stopped after one $0.01 test transfer. It went through.
Telling them
I wrote it up. Screenshots of the 401 vs 200. The ffuf output. The exact path rewrite behavior. They fixed it the next day.
Switched from HTTP API to REST API (stricter path matching)
Added userId validation in every Lambda, not just the authorizer.
I got $12,000 bounty for it. Planning to go to Dubai 🙂
Leave a Comment Cancel Reply<br>Your email address will not be published. Required fields are marked *<br>Type here..
Name*
Email*
Website
Save my name, email, and website in this browser for the next time I comment.
Customize<br>Reject All<br>Accept All
Powered by
Necessary Cookies
Always Active
Necessary cookies enable essential site features like secure log-ins and consent preference adjustments. They do not store personal data.
None
Functional Cookies<br>Remark
Functional cookies support features like content sharing on social media, collecting feedback, and enabling third-party tools.
None
Analytical Cookies<br>Remark
Analytical cookies track visitor interactions, providing insights on metrics like visitor count, bounce rate, and traffic sources.
None
Advertisement Cookies<br>Remark
Advertisement cookies deliver personalized ads based on your previous visits and analyze the effectiveness of ad campaigns.
None
Unclassified Cookies<br>Remark
Unclassified cookies are cookies that we are in the process of classifying, together with the providers of individual cookies.
None
Reject All<br>Save My Preferences<br>Accept All
Powered by
Scroll to Top