August 31, 2026
My Autonomous Bug Hunting Harness Found an SSRF Filter Bypass Hidden Behind a Redirect
Introduction
By redhunter01
9 min read
Introduction
One of the biggest advantages of building your own security automation isn't simply being able to scan more endpoints.
It's being able to automate the reasoning process around a vulnerability class.
I built a fully autonomous bug-hunting harness designed to discover and validate web vulnerabilities by:
- Mapping attack surfaces
- Identifying interesting parameters
- Detecting server-side URL fetching behavior
- Generating security test cases
- Observing application responses
- Comparing results against control requests
- Chaining related behaviors
- Escalating promising findings into deeper tests
- Producing evidence for manual validation
During one of its autonomous hunting workflows, the harness identified an interesting URL-fetching endpoint.
The obvious SSRF tests were blocked.
That would normally be a dead end.
But the harness didn't stop after seeing:
Localhost URLs are not allowedLocalhost URLs are not allowedIt recognized that the application appeared to have an SSRF protection mechanism and continued testing how that protection behaved across different request states.
One of those tests involved HTTP redirects.
That uncovered an SSRF filter bypass.
The application correctly blocked a direct request to:
127.0.0.1127.0.0.1but allowed a public URL that redirected the server to:
127.0.0.1127.0.0.1The server then made the redirected request to its own loopback interface.
The confirmed impact was:
- Unauthenticated SSRF to
127.0.0.1 - Bypass of the application's anti-SSRF filter
- Internal port enumeration
- Internal HTTP service probing
- Path/status-based reconnaissance against localhost services
The issue was ultimately accepted and resulted in a $100 bounty.
More importantly, this was a good demonstration of why autonomous security tooling should test security assumptions and state transitions, rather than simply running static payload lists.
1. The Goal: Build a Hunter That Can Think in Chains
Traditional scanners often operate like this:
Find endpoint
β
Insert payload
β
Check response
β
Next payloadFind endpoint
β
Insert payload
β
Check response
β
Next payloadThat works for simple vulnerabilities.
But many modern web vulnerabilities require multiple steps.
For example:
Request A
β
Application behavior
β
Redirect
β
Request B
β
Different security boundary
β
Unexpected behaviorRequest A
β
Application behavior
β
Redirect
β
Request B
β
Different security boundary
β
Unexpected behaviorI wanted my hunting harness to recognize those relationships.
The idea was to make the system capable of asking:
"What can I do with the behavior I just discovered?"
rather than:
"Which payload should I try next?"
That distinction became important in this hunt.
2. The Autonomous Discovery Workflow
The relevant workflow looked approximately like this:
Target
β
Attack-surface discovery
β
Endpoint classification
β
Parameter analysis
β
Behavior detection
β
Vulnerability hypothesis
β
Baseline request
β
Security-control detection
β
Bypass hypothesis generation
β
Chained request testing
β
Differential analysis
β
Evidence collection
β
Manual verificationTarget
β
Attack-surface discovery
β
Endpoint classification
β
Parameter analysis
β
Behavior detection
β
Vulnerability hypothesis
β
Baseline request
β
Security-control detection
β
Bypass hypothesis generation
β
Chained request testing
β
Differential analysis
β
Evidence collection
β
Manual verificationFor SSRF specifically, the harness looked for functionality where the server appeared to retrieve attacker-controlled URLs.
That included parameters resembling:
url=
uri=
target=
endpoint=
callback=
redirect=
feed=
proxy=url=
uri=
target=
endpoint=
callback=
redirect=
feed=
proxy=It then classified endpoints based on their observed behavior rather than relying exclusively on parameter names.
3. The Endpoint That Triggered the SSRF Workflow
The harness identified a URL-processing endpoint:
GET /check?url=<URL>GET /check?url=<URL>The interesting property was that the supplied URL was processed server-side.
That made the endpoint a potential SSRF sink.
The harness created a hypothesis:
User-controlled URL
β
Server-side network request
β
Potential SSRFUser-controlled URL
β
Server-side network request
β
Potential SSRFIt then began testing the application's network restrictions.
4. First Autonomous Test: Localhost
The first SSRF test targeted the loopback interface.
Conceptually:
http://127.0.0.1:8080/http://127.0.0.1:8080/The application responded with:
Localhost URLs are not allowedLocalhost URLs are not allowedFrom a conventional scanner's perspective:
SSRF payload
β
Blocked
β
StopSSRF payload
β
Blocked
β
StopBut the harness classified the response differently.
It recognized that the application wasn't simply rejecting URLs.
It was specifically performing SSRF-related security validation.
That created a second hypothesis:
There is an SSRF filter. Can the request lifecycle cause the application to make a destination change after validation?
5. Mapping the SSRF Protection
The harness continued testing the boundaries of the filter.
A private address such as:
10.0.0.110.0.0.1was rejected:
Private or reserved IP addresses are not allowedPrivate or reserved IP addresses are not allowedThe cloud metadata address:
169.254.169.254169.254.169.254was also rejected.
Alternative representations of localhost were tested as well.
For example:
21307064332130706433and:
0x7f0000010x7f000001were rejected as alternative IP notation.
This was valuable because the harness had now learned something about the application's security model.
It wasn't simply:
"URL allowed""URL allowed"or:
"URL blocked""URL blocked"It appeared to be performing destination-aware SSRF filtering.
6. The Important Hypothesis
At this point, the interesting question became:
Does the application re-run the SSRF validation if the destination changes?
HTTP redirects are perfect for testing this assumption.
Consider:
Request #1
Public URL
|
v
HTTP 302
|
v
Request #2
127.0.0.1Request #1
Public URL
|
v
HTTP 302
|
v
Request #2
127.0.0.1The first destination is public.
The second destination is internal.
If the filter only evaluates Request #1, the security boundary can be bypassed.
The autonomous workflow generated this as a next-stage test.
7. Redirect-Based SSRF Testing
The harness used a publicly reachable redirector that could produce a response equivalent to:
HTTP/1.1 302 Found
Location: http://127.0.0.1:8080/HTTP/1.1 302 Found
Location: http://127.0.0.1:8080/The important point was that the initial URL itself was public.
Therefore:
Initial URL
β
Public
β
Passes validationInitial URL
β
Public
β
Passes validationThe server then received:
Location: http://127.0.0.1:8080/Location: http://127.0.0.1:8080/The critical question:
Does the server validate the new URL?Does the server validate the new URL?The observed behavior showed that it followed the redirect and reached the loopback destination.
8. The Autonomous Detection
The harness observed a significant change in the application's response.
The resulting evidence indicated:
serverIpAddress = 127.0.0.1serverIpAddress = 127.0.0.1That was the signal that turned the test from:
Interesting redirect behaviorInteresting redirect behaviorinto:
Confirmed server-side internal requestConfirmed server-side internal requestThe attack chain was:
External attacker
|
v
Public URL
|
v
302 Redirect
|
v
Vulnerable URL fetcher
|
v
127.0.0.1:8080External attacker
|
v
Public URL
|
v
302 Redirect
|
v
Vulnerable URL fetcher
|
v
127.0.0.1:8080The harness flagged the behavior as a likely SSRF filter bypass.
I then manually validated the finding and its scope.
9. Why the Automation Was Interesting
The interesting part wasn't that automation generated a redirect.
That's relatively easy.
The interesting part was the sequence of decisions.
The system effectively learned:
Direct localhost
β
Blocked
β
Therefore an SSRF filter exists
β
Test filter boundaries
β
Protection still works
β
Look for state-changing behavior
β
Redirect changes destination
β
Test whether validation repeats
β
Internal destination reachedDirect localhost
β
Blocked
β
Therefore an SSRF filter exists
β
Test filter boundaries
β
Protection still works
β
Look for state-changing behavior
β
Redirect changes destination
β
Test whether validation repeats
β
Internal destination reachedThis is the type of workflow I wanted the autonomous harness to perform.
The vulnerability wasn't found by blindly throwing thousands of payloads at the application.
It was found by chaining observations.
10. Proving the Internal Service
After the initial detection, I wanted to determine whether the loopback access was actually useful.
A request to:
127.0.0.1:8080127.0.0.1:8080produced:
HTTP 406HTTP 406That was important.
The response demonstrated that something on the server's loopback interface was actively processing the request.
I then compared that with ports that produced:
Connection refused by hostConnection refused by hostThis created a clear distinction:
Open/reachable service
β
HTTP responseOpen/reachable service
β
HTTP responseversus:
Unavailable service
β
Connection refusedUnavailable service
β
Connection refusedThis meant the SSRF could be used as a limited internal port-discovery oracle.
11. Path-Level Reconnaissance
The same behavior could be used to test paths on reachable HTTP services.
For example:
127.0.0.1:8080/127.0.0.1:8080/and:
127.0.0.1:8080/actuator/health127.0.0.1:8080/actuator/healthproduced different application behavior.
This demonstrated that the primitive wasn't limited to determining whether a port was open.
It could also provide information about HTTP paths exposed by localhost services.
Conceptually:
SSRF
β
127.0.0.1:8080
β
Path
β
HTTP response
β
Reconnaissance signalSSRF
β
127.0.0.1:8080
β
Path
β
HTTP response
β
Reconnaissance signal12. Differential Testing
One of the techniques built into the hunting workflow is differential analysis.
Instead of asking:
"Does this request return something interesting?"
the system compares related requests.
For example:
Control:
Public URL β Public destinationControl:
Public URL β Public destinationversus:
Test:
Public URL β 127.0.0.1Test:
Public URL β 127.0.0.1The application reported the destination IP associated with the request.
For the public control, it reported the external destination.
For the redirect test:
127.0.0.1127.0.0.1was observed.
This greatly increased confidence that the server β not the client β was making the internal request.
13. Testing the Boundaries
After confirming SSRF, I didn't assume that every internal destination was reachable.
The next stage was scope determination.
The testing established the following:
TargetResult127.0.0.1β
Reached127.0.0.1:8080β
HTTP responseOther tested localhost portsβ
/β Depending on service state10.0.0.1β Blocked172.31.0.1β Blocked169.254.169.254β BlockedArbitrary internal response bodyβ Not demonstrated
This distinction is important.
The confirmed vulnerability was specifically a loopback SSRF filter bypass, not unrestricted access to the entire internal network.
14. Cloud Metadata Testing
Cloud metadata endpoints are an obvious SSRF target.
I tested:
169.254.169.254169.254.169.254through the redirect path.
The request did not successfully reach the metadata service.
The existing protection continued to prevent access.
No credentials were obtained.
This was an important negative result.
A good bug bounty report should document not only what works, but also what doesn't.
15. No Arbitrary Response-Body Disclosure
I also investigated whether the SSRF could be turned into a generic internal HTTP response reader.
It could not be demonstrated as such.
The application processed specific RDAP-related response fields rather than exposing arbitrary response bodies.
Therefore, I did not claim:
"Full arbitrary internal response disclosure."
Instead, the confirmed impact remained:
Unauthenticated SSRF
+
Loopback access
+
Port probing
+
Path probing
+
Status-based reconnaissanceUnauthenticated SSRF
+
Loopback access
+
Port probing
+
Path probing
+
Status-based reconnaissanceThis is an important distinction when assessing severity.
16. What the Harness Did vs. What I Verified
The autonomous system was responsible for identifying and prioritizing the suspicious behavior.
The final security conclusion was manually verified.
That distinction matters.
The workflow looked like:
Autonomous discovery
β
Interesting behavior
β
Automated evidence collection
β
Candidate vulnerability
β
Manual reproduction
β
Manual scope testing
β
Final reportAutonomous discovery
β
Interesting behavior
β
Automated evidence collection
β
Candidate vulnerability
β
Manual reproduction
β
Manual scope testing
β
Final reportI don't consider an automated alert by itself to be a vulnerability report.
Automation should reduce the search space.
Human validation should establish the actual security impact.
17. The Root Cause
The underlying issue was an incomplete SSRF validation boundary.
The application correctly validated the initial destination.
Conceptually:
Initial URL
|
v
Resolve
|
v
Validate IP
|
v
Allowed
|
v
RequestInitial URL
|
v
Resolve
|
v
Validate IP
|
v
Allowed
|
v
RequestBut after the server received a redirect:
Initial URL
|
v
Validation β
|
v
Request
|
v
302 Redirect
|
v
New URL
|
X
Validation not consistently applied
|
v
127.0.0.1Initial URL
|
v
Validation β
|
v
Request
|
v
302 Redirect
|
v
New URL
|
X
Validation not consistently applied
|
v
127.0.0.1The security control therefore protected the initial destination but failed to protect the subsequent redirected destination.
18. Why This Is a Valuable Bug Hunting Pattern
This finding demonstrates a broader principle.
Security controls frequently make assumptions about application state.
For example:
"URL was validated.""URL was validated."But the real question is:
"Is every network connection made as a result of that URL validated?"
Those are different questions.
The same mindset can apply beyond SSRF.
When testing a security control, look for:
State changes
Redirects
Retries
Callbacks
Background jobs
Secondary requests
DNS resolution
Parser transformations
Protocol upgradesState changes
Redirects
Retries
Callbacks
Background jobs
Secondary requests
DNS resolution
Parser transformations
Protocol upgradesThe initial security decision may not apply to the entire execution chain.
19. How I Would Generalize This Into an Autonomous SSRF Module
A useful autonomous SSRF workflow can be represented as:
Discover URL sink
β
Confirm server-side fetching
β
Establish public control
β
Test direct internal destinations
β
Identify security controls
β
Model blocked destinations
β
Generate transformation hypotheses
β
Test redirects
β
Test redirect chains
β
Compare destination observations
β
Determine reachable scope
β
Generate evidence
β
Manual verificationDiscover URL sink
β
Confirm server-side fetching
β
Establish public control
β
Test direct internal destinations
β
Identify security controls
β
Model blocked destinations
β
Generate transformation hypotheses
β
Test redirects
β
Test redirect chains
β
Compare destination observations
β
Determine reachable scope
β
Generate evidence
β
Manual verificationThe important part is the feedback loop.
The output of one test should influence the next test.
For example:
localhost blocked
β
Filter detected
β
Ask how destination can change
β
Redirect candidate
β
Test redirect
β
Internal destination reachedlocalhost blocked
β
Filter detected
β
Ask how destination can change
β
Redirect candidate
β
Test redirect
β
Internal destination reachedThat's much more powerful than:
Payload #1
Payload #2
Payload #3
Payload #4
...Payload #1
Payload #2
Payload #3
Payload #4
...20. Lessons for Bug Bounty Hunters
Lesson 1 β A blocked payload is information
When you see:
Localhost URLs are not allowedLocalhost URLs are not alloweddon't necessarily move on.
You just learned something about the application's security architecture.
Lesson 2 β Test the security control, not just the vulnerability
Instead of asking:
"Can I exploit SSRF?"
ask:
"What exactly is the application doing to prevent SSRF?"
Once you understand the defense, you can test whether its assumptions hold.
Lesson 3 β Think in state transitions
Many interesting vulnerabilities occur when an application moves from:
State AState Ato:
State BState Bwithout repeating the security checks that applied to State A.
Redirects are a perfect example.
Lesson 4 β Build feedback into automation
A mature hunting system shouldn't treat every test independently.
It should be able to reason:
Observation
β
Hypothesis
β
New test
β
Observation
β
Updated hypothesisObservation
β
Hypothesis
β
New test
β
Observation
β
Updated hypothesisThat feedback loop is what makes automation significantly more useful.
Lesson 5 β Differential analysis is extremely powerful
A single response can be ambiguous.
Two carefully chosen responses can reveal much more.
For SSRF:
Public destinationPublic destinationversus:
Public β redirect β localhostPublic β redirect β localhostcan provide strong evidence of the actual network destination.
Lesson 6 β Don't overclaim
The fact that localhost was reachable did not mean:
"Entire internal network compromised.""Entire internal network compromised."The tested boundaries showed that private network and metadata targets remained blocked.
Accurate scope is more valuable than an exaggerated impact statement.
Lesson 7 β Stop once you have enough evidence
After establishing:
Unauthenticated
+
SSRF
+
Redirect bypass
+
127.0.0.1 reached
+
Internal service responseUnauthenticated
+
SSRF
+
Redirect bypass
+
127.0.0.1 reached
+
Internal service responsethere was no need to exploit the internal service.
The objective is to prove the vulnerability safely.
21. The Complete Discovery Chain
The entire autonomous discovery can be summarized as:
Autonomous attack-surface discovery
|
v
URL-fetching endpoint identified
|
v
Server-side request confirmed
|
v
Direct localhost test
|
v
Blocked
|
v
SSRF security control identified
|
v
Filter boundary analysis
|
v
Redirect hypothesis generated
|
v
Public URL β 302 β localhost
|
v
Redirect destination reached
|
v
127.0.0.1 confirmed
|
v
Internal service identified
|
v
Port/path probing demonstrated
|
v
Manual validation
|
v
Responsible disclosure
|
v
$100 BountyAutonomous attack-surface discovery
|
v
URL-fetching endpoint identified
|
v
Server-side request confirmed
|
v
Direct localhost test
|
v
Blocked
|
v
SSRF security control identified
|
v
Filter boundary analysis
|
v
Redirect hypothesis generated
|
v
Public URL β 302 β localhost
|
v
Redirect destination reached
|
v
127.0.0.1 confirmed
|
v
Internal service identified
|
v
Port/path probing demonstrated
|
v
Manual validation
|
v
Responsible disclosure
|
v
$100 Bounty22. Final Takeaway
The most interesting part of this vulnerability wasn't the SSRF payload.
It was the reasoning chain that led to it.
The application already had defenses against SSRF.
It blocked:
127.0.0.1
10.0.0.1
169.254.169.254127.0.0.1
10.0.0.1
169.254.169.254and even rejected alternate IP representations.
A conventional scanner could easily have reported:
SSRF: blockedSSRF: blockedand moved on.
Instead, the autonomous hunting workflow treated the security response as useful information.
It asked:
If the first destination is validated, what happens when the destination changes?
That led to:
Public URL
β
302 Redirect
β
127.0.0.1
β
Internal HTTP servicePublic URL
β
302 Redirect
β
127.0.0.1
β
Internal HTTP serviceThe key lesson is broader than SSRF:
Don't only test whether a security control blocks an attack. Test whether the control remains valid throughout the entire execution flow.
For autonomous bug hunting, this is especially important.
A useful security agent shouldn't simply know thousands of payloads.
It should be able to observe:
"What happened?""What happened?"then reason:
"Why did that happen?""Why did that happen?"and finally decide:
"What should I test next?""What should I test next?"That feedback loop is what turns automated scanning into something much closer to autonomous vulnerability research.
Disclosure & Bounty
The vulnerability was responsibly disclosed with reproduction steps, evidence demonstrating the redirect-based filter bypass, impact analysis, tested boundaries, and remediation guidance.
The report was accepted and resulted in a: