Back to Articles

Fuzz Lightyear: Finding Authorization Bugs in Microservices Before Attackers Do

[ View on GitHub ]

Fuzz Lightyear: Finding Authorization Bugs in Microservices Before Attackers Do

Hook

Most API security testing treats each endpoint in isolation, but the most dangerous vulnerabilities emerge when you chain requests together—creating objects as one user and accessing them as another. That’s the attack vector traditional testing misses.

Context

When Yelp scaled to hundreds of microservices, they faced a classic distributed systems security problem: authorization boundaries that work perfectly in isolation break down when services interact. A user might legitimately create a reservation through Service A, but Service B might fail to verify ownership before allowing modifications. These Insecure Direct Object Reference (IDOR) vulnerabilities are among the most common and exploitable flaws in microservice architectures, consistently appearing in OWASP’s Top 10.

Traditional DAST tools scan individual endpoints with malformed inputs, checking for SQL injection or XSS. But they struggle with stateful authorization testing across service boundaries. How do you systematically verify that every resource created by User A cannot be accessed, modified, or deleted by User B? Manual testing doesn’t scale when you’re deploying dozens of services weekly. Yelp built fuzz-lightyear to solve this: a framework that treats authorization testing as a property-based testing problem, generating sequences of authenticated requests to discover the edge cases where access controls fail.

Technical Insight

Security Testing

API endpoints & parameters

endpoint graph

generated test cases

realistic test data

chained HTTP requests

responses

analyze auth & validation

cURL commands

Swagger/OpenAPI Spec

Endpoint Discovery Parser

Hypothesis Test Generator

Stateful Request Sequencer

Pytest Fixture System

Vulnerability Detectors

HTTP Request Executor

Vulnerability Reporter

Reproducible Exploits

System architecture — auto-generated

Fuzz-lightyear’s architecture revolves around three core concepts: Swagger-driven endpoint discovery, Hypothesis-powered fuzzing, and pytest’s fixture system adapted for stateful security testing. When you point it at a microservice, it parses the OpenAPI specification to build a graph of available endpoints and their parameters, then uses Hypothesis to generate test cases that chain requests together in ways developers rarely anticipate.

The framework introduces a critical distinction between “expected failures” and “successful malicious requests.” A DELETE request that returns 403 Forbidden is working correctly. A DELETE request that returns 200 OK when it should have returned 403 is a vulnerability. Here’s how you configure a basic IDOR test:

from fuzz_lightyear import FuzzLightyearTestCase

class TestReservations(FuzzLightyearTestCase):
    @pytest.fixture
    def victim_reservation(self):
        # Create a resource as the victim user
        with self.client.login(user='victim@example.com'):
            response = self.client.post('/reservations', {
                'restaurant_id': 123,
                'party_size': 4
            })
            return response.json()['id']
    
    def test_idor_on_reservation_deletion(self, victim_reservation):
        # Attempt to delete victim's resource as attacker
        with self.client.login(user='attacker@example.com'):
            response = self.client.delete(f'/reservations/{victim_reservation}')
            
            # This should fail with 403/404, not succeed
            assert response.status_code >= 400, \
                f"IDOR: Attacker deleted victim's reservation. " \
                f"curl -X DELETE {response.request.url}"

The fixture system here mirrors pytest, but with security-specific semantics. The victim_reservation fixture performs authenticated actions as one user, then the test body switches context to verify that a different user cannot perform unauthorized operations. When a vulnerability is detected, fuzz-lightyear outputs the exact cURL command sequence needed to reproduce it—invaluable for filing actionable bug reports.

What makes this approach powerful is how it scales across microservice boundaries. Suppose your reservation service delegates payment processing to a separate billing service. You can define fixtures that span both services:

@pytest.fixture
def paid_reservation(self, victim_reservation):
    with self.client.login(user='victim@example.com'):
        # Add payment info via billing service
        payment_response = self.billing_client.post('/payments', {
            'reservation_id': victim_reservation,
            'card_token': 'tok_visa'
        })
        return {
            'reservation_id': victim_reservation,
            'payment_id': payment_response.json()['id']
        }

Fuzz-lightyear will then explore state spaces like “can an attacker refund a payment they didn’t make” or “can an attacker modify a reservation after someone else paid for it”—precisely the cross-service authorization bugs that emerge in distributed systems.

The Hypothesis integration enables property-based fuzzing where the framework generates variations of valid inputs, including edge cases like extremely long strings, negative numbers, or special characters in IDs. Rather than testing with a handful of hardcoded examples, it generates hundreds of test cases, searching for the specific input combination that triggers unauthorized access. This is chaos engineering applied to security: injecting unexpected but technically valid requests to expose system weaknesses.

The plugin architecture allows extending vulnerability detection beyond IDOR. Yelp includes plugins for detecting authentication bypass, mass assignment vulnerabilities, and excessive data exposure. Each plugin hooks into the request/response lifecycle, examining whether responses leak information they shouldn’t or whether endpoints accept parameters that should be restricted.

Gotcha

Fuzz-lightyear’s effectiveness is directly proportional to your Swagger documentation quality. If your OpenAPI spec doesn’t accurately reflect authentication requirements, parameter constraints, or possible response codes, the fuzzer will generate false positives or miss real vulnerabilities. Teams that treat API documentation as an afterthought will find themselves writing fixtures to work around incomplete specs, defeating much of the automation benefit.

The fixture system, while powerful, requires significant upfront investment for complex ecosystems. If your reservation flow involves creating users, verifying emails, adding payment methods, creating reservations, and processing payments across five different services, you’ll need fixtures that orchestrate all these steps. This becomes a maintenance burden—when service APIs evolve, fixtures break. For teams already struggling with microservice complexity, adding a parallel fixture ecosystem might be too much operational overhead. Additionally, since the project’s last significant update was several years ago, you may encounter compatibility issues with newer Python versions, pytest releases, or Swagger 3.0 features. The lack of recent maintenance is a legitimate concern for adopting this in production security workflows.

Verdict

Use if: You’re operating a microservice architecture with well-maintained Swagger/OpenAPI documentation and need automated testing for authorization vulnerabilities, especially IDOR across service boundaries. This is particularly valuable if you’re frequently shipping new endpoints and want continuous security validation integrated into CI/CD pipelines. Teams already comfortable with pytest will appreciate the familiar mental model applied to security testing. Skip if: Your APIs lack comprehensive OpenAPI specs, you’re working with GraphQL or gRPC services, or you need actively maintained tooling with vendor support. Also skip if your team lacks the bandwidth to build and maintain the fixture ecosystem required for complex, multi-service test scenarios. For simpler use cases or teams wanting something more turnkey, Schemathesis offers similar stateful fuzzing with better ongoing development and broader protocol support.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/ai-dev-tools/yelp-fuzz-lightyear.svg)](https://starlog.is/api/badge-click/ai-dev-tools/yelp-fuzz-lightyear)