{
  "paths": {
    "/api/tools/echo": {
      "get": {
        "responses": {
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "api"
        ]
      },
      "post": {
        "responses": {
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "api"
        ]
      },
      "put": {
        "responses": {
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "api"
        ]
      },
      "patch": {
        "responses": {
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "api"
        ]
      },
      "delete": {
        "responses": {
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "api"
        ]
      }
    },
    "/api/tools/otp": {
      "get": {
        "parameters": [
          {
            "in": "query",
            "name": "seed_b32",
            "description": "Base32 seed for TOTP generation",
            "schema": {
              "type": "string"
            },
            "required": false
          },
          {
            "in": "query",
            "name": "seed_hex",
            "description": "Hex seed for TOTP generation",
            "schema": {
              "type": "string"
            },
            "required": false
          }
        ],
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OtpResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "summary": "Get TOTP code via query parameter",
        "tags": [
          "api"
        ]
      },
      "post": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OtpResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/OtpArgs"
              }
            }
          }
        },
        "summary": "Get TOTP code via form data",
        "tags": [
          "api"
        ]
      }
    },
    "/api/v1/header-cookie": {
      "get": {
        "responses": {
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "api"
        ]
      }
    },
    "/api/v1/header-cookie-auth": {
      "get": {
        "responses": {
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "api"
        ]
      }
    },
    "/api/v1/users/{user_id}": {
      "get": {
        "parameters": [
          {
            "in": "path",
            "name": "user_id",
            "description": "User ID to search for",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK"
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "api"
        ]
      },
      "parameters": [
        {
          "in": "path",
          "name": "user_id",
          "required": true,
          "schema": {
            "type": "string",
            "minLength": 1
          }
        }
      ]
    },
    "/api/v1/get-token": {
      "post": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetTokenResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetTokenArgs"
              }
            }
          }
        },
        "summary": "{\n   \"auth\": {\n       \"username\": \"admin\",\n       \"password\": \"easypassword\"\n   }\n}",
        "tags": [
          "api"
        ]
      }
    },
    "/api/v1/get-token-form": {
      "post": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetTokenResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/Auth"
              }
            }
          }
        },
        "tags": [
          "api"
        ]
      }
    },
    "/api/v1/is-valid-token": {
      "get": {
        "responses": {
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "api"
        ]
      },
      "post": {
        "responses": {
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "api"
        ]
      }
    },
    "/api/v1/graphql": {
      "post": {
        "responses": {
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "summary": "GraphQL API endpoint - returns JSON responses.\nVULNERABLE: SQL injection, no query depth limiting, introspection enabled.",
        "description": "Example POST body:\n{\n    \"query\": \"{ users { id username email } }\"\n}",
        "tags": [
          "api"
        ]
      }
    },
    "/api/v1/graphql/schema": {
      "get": {
        "responses": {
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "summary": "Export GraphQL schema via introspection query (returns JSON).",
        "tags": [
          "api"
        ]
      }
    },
    "/api/v1/oauth2/token": {
      "post": {
        "responses": {
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "summary": "OAuth2 Token Endpoint. Supports two grant types:",
        "description": "1. authorization_code - Exchange an auth code for a token (user flow)\n2. client_credentials - Get a token directly with client ID/secret (machine-to-machine)\n\nVULNERABLE:\n- No client_secret validation on authorization_code grant (accepts any or none)\n- Tokens are predictable (MD5-based)\n- Auth codes can be replayed (not invalidated)\n- client_credentials accepts any scope without validation\n\nPOST body (form or JSON):\n    grant_type: authorization_code | client_credentials\n    code: <authorization_code>          (authorization_code only)\n    client_id: vulapp-client-001\n    client_secret: super-secret-client-secret\n    redirect_uri: <must match original>  (authorization_code only)\n    scope: read profile                  (client_credentials only)",
        "tags": [
          "api"
        ]
      }
    },
    "/api/v1/oauth2/userinfo": {
      "get": {
        "responses": {
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "summary": "OAuth2 UserInfo Endpoint - returns profile for a valid Bearer token.",
        "tags": [
          "api"
        ]
      }
    },
    "/api/v1/waf": {
      "get": {
        "responses": {
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "summary": "Simulate a WAF (Web Application Firewall) block - returns JSON.",
        "tags": [
          "api"
        ]
      },
      "post": {
        "responses": {
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "summary": "Simulate a WAF (Web Application Firewall) block - returns JSON.",
        "tags": [
          "api"
        ]
      }
    }
  },
  "info": {
    "title": "Vulnerable App API",
    "version": "v1"
  },
  "tags": [
    {
      "name": "api",
      "description": "Operations on API"
    }
  ],
  "openapi": "3.0.2",
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "code": {
            "type": "integer",
            "description": "Error code"
          },
          "status": {
            "type": "string",
            "description": "Error name"
          },
          "message": {
            "type": "string",
            "description": "Error message"
          },
          "errors": {
            "type": "object",
            "description": "Errors",
            "additionalProperties": {}
          }
        },
        "additionalProperties": false
      },
      "PaginationMetadata": {
        "type": "object",
        "properties": {
          "total": {
            "type": "integer",
            "description": "Total number of items."
          },
          "total_pages": {
            "type": "integer",
            "description": "Total number of pages."
          },
          "first_page": {
            "type": "integer",
            "description": "First available page number."
          },
          "last_page": {
            "type": "integer",
            "description": "Last available page number."
          },
          "page": {
            "type": "integer",
            "description": "Current page number."
          },
          "previous_page": {
            "type": "integer",
            "description": "Previous page number."
          },
          "next_page": {
            "type": "integer",
            "description": "Next page number."
          }
        },
        "additionalProperties": false
      },
      "OtpResponse": {
        "type": "object",
        "properties": {
          "otp_code": {
            "type": "string",
            "description": "The generated TOTP code"
          },
          "time_remaining": {
            "type": "number",
            "description": "Seconds until the code expires"
          },
          "seed_b32": {
            "type": "string",
            "description": "The seed used in base32 (generated if not provided)"
          },
          "seed_hex": {
            "type": "string",
            "description": "The seed used in hex (generated if not provided)"
          }
        },
        "additionalProperties": false
      },
      "OtpArgs": {
        "type": "object",
        "properties": {
          "seed_b32": {
            "type": "string",
            "description": "Base32 seed for TOTP generation"
          },
          "seed_hex": {
            "type": "string",
            "description": "Hex seed for TOTP generation"
          }
        },
        "additionalProperties": false
      },
      "Auth": {
        "type": "object",
        "properties": {
          "username": {
            "type": "string"
          },
          "password": {
            "type": "string"
          }
        },
        "required": [
          "password",
          "username"
        ],
        "additionalProperties": false
      },
      "GetTokenArgs": {
        "type": "object",
        "properties": {
          "auth": {
            "$ref": "#/components/schemas/Auth"
          }
        },
        "required": [
          "auth"
        ],
        "additionalProperties": false
      },
      "TokenReply": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string"
          },
          "prefix": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "GetTokenResponse": {
        "type": "object",
        "properties": {
          "reply": {
            "$ref": "#/components/schemas/TokenReply"
          }
        },
        "additionalProperties": false
      }
    },
    "responses": {
      "DEFAULT_ERROR": {
        "description": "Default error response",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "UNPROCESSABLE_CONTENT": {
        "description": "Unprocessable Content",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  }
}