Back to Guides

    API9:2023 - Improper Inventory Management

    Improper Inventory Management happens when APIs expose undocumented, deprecated, or forgotten endpoints that remain reachable and often weaker than the current surface.

    1. What Is It?

    Improper Inventory Management happens when an API exposes endpoints that are not properly tracked, documented, or maintained.

    These endpoints often include legacy versions, deprecated routes, hidden features, or internal tools that remain accessible even after newer and more secure implementations are introduced.

    The critical issue is not just that these endpoints exist — but that they are forgotten, inconsistent, or weaker than the main API surface.

    2. Why It Matters

    • Legacy endpoints often have weaker or outdated security
    • Undocumented APIs bypass normal review processes
    • Attackers actively search for forgotten routes
    • Security fixes are applied to new versions, not old ones

    OWASP classifies this risk because modern systems evolve quickly, but old endpoints are rarely removed. These forgotten surfaces often become the weakest entry point into an otherwise secure system.

    Read the OWASP Definition

    3. How It Happens (Technical)

    This issue appears when API versions, routes, or services are not properly tracked and maintained over time.

    # secure (v2)
    @app.get("/api/v2/admin/reports")
    def reports_v2(claims):
        if claims["role"] != "admin":
            raise HTTPException(status_code=403)
        return {"status": "restricted"}
    # vulnerable (v1 legacy)
    @app.get("/api/v1/admin/reports")
    def reports_v1(claims):
        return {"export": "full data", "flag": FLAG}

    The same functionality exists in two places, but only the new version enforces proper authorization.

    Key concept: attackers do not break secure endpoints. They find older, weaker ones.

    Attacker’s Perspective

    • Enumerate versions: /v1, /v2, /beta
    • Search for undocumented endpoints
    • Compare behavior across versions
    • Target the weakest implementation

    4. Real-World Example

    This benchmark models a system where a secure API version exists, but an older version remains exposed with weaker controls.

    • GET /api/v2/admin/reports → correctly restricted
    • GET /api/v1/admin/reports → legacy, weak
    # v2 (secure)
    if claims.get("role") != "admin":
        raise HTTPException(status_code=403)
    # v1 (vulnerable)
    return {
        "version": "v1",
        "export": "legacy full export",
        "flag": FLAG,
    }
    Legacy endpoint skips role validation

    Even though the new version is secure, the old version exposes full admin data to non-admin users.

    Attack flow:

    1. Login as support user
    2. Test v2 → blocked
    3. Test v1 → succeeds
    4. Extract sensitive data

    Common Variations

    • Deprecated API versions still active
    • Shadow or undocumented endpoints
    • Internal tools exposed externally
    • Test/debug routes left enabled

    5. How To Prevent

    • Maintain a complete API inventory
    • Remove deprecated endpoints aggressively
    • Ensure security parity across versions
    • Monitor and audit exposed routes regularly
    GOOD:
    Only /v2 exists
    
    BAD:
    v1 (weak) + v2 (secure) both exposed

    If an endpoint exists, it must be secured — even if it is deprecated.

    6. Detection Tips (Scanner Perspective)

    • Enumerate API versions automatically
    • Compare responses across versions
    • Test undocumented endpoints
    • Look for inconsistent authorization behavior

    7. Final Takeaway

    API9 is about exposure through forgotten surfaces.

    You are not only securing your API — you are securing every version of it.