Broken Crystals Security Benchmark

repository·stable·Indexed 41 days ago

https://github.com/neuralegion/brokencrystals

A security benchmark application featuring a React client and Node.js backend designed to implement and demonstrate common security vulnerabilities for testing and educational purposes. It includes REST, GraphQL, and gRPC endpoints, and provides a wide array of intentional flaws including JWT authentication bypass, XSS, OS command injection, LFI, and LDAP injection.

Tokens
24.3K
Snippets
86
Records
109
Agent score
52%

What's inside Broken Crystals

  1. Overview of Broken Crystals

    stable

    Broken Crystals is a benchmark application designed to demonstrate common security vulnerabilities using modern technologies. It consists of a React-based web client and a Node.js server that provides both OpenAPI (REST) and GraphQL endpoints.

    Available Endpoints:

    • Web Client & API: http://localhost:3000
    • Swagger UI: http://localhost:3000/swagger (for REST API documentation)
    • Swagger JSON: http://localhost:3000/swagger-json
    • GraphiQL UI: http://localhost:3000/graphiql (for GraphQL documentation)

    Note: The GraphQL API currently has fewer supported endpoints than the REST API.

  2. Vulnerability Overview: BrokenCrystals API

    stable

    The BrokenCrystals project serves as a demonstration of various security vulnerabilities within its API endpoints. Key vulnerability categories identified include:

    • Sensitive Information Disclosure: Endpoints like /api/config expose API keys, database connection strings, and cloud credentials.
    • Server-Side Template Injection (SSTI): The /api/render endpoint is vulnerable to code execution via the doT templating engine.
    • Server-Side Request Forgery (SSRF): The /api/file endpoint allows fetching internal or external resources, including cloud metadata.
    • SQL Injection (SQLi): Multiple endpoints (/api/testimonials/count, /api/products/views, /api/products/search) are vulnerable to SQL manipulation.
    • Unvalidated Redirect: The /api/goto endpoint allows arbitrary redirects.
    • Version Control Exposure: .git and .hg directories are publicly accessible.
    • XML External Entity (XXE): The /api/metadata endpoint is vulnerable to XXE attacks.
    • Broken Object Property Level Authorization (BOPLA): The /api/users/me endpoint allows unauthorized updates to sensitive user fields.
  3. Exploit Prototype Pollution in /marketplace and /api/email/sendSupportEmail

    stable

    Prototype pollution vulnerabilities exist in both client-side and server-side contexts within this application.

    Client-side (via /marketplace)

    Parsing URI parameters for portfolio filtering allows for object property injection.

    • Property Injection: A request like /marketplace?__proto__[TestKey]=TestValue creates Object.TestKey.
    • DOM XSS: Use the payload __proto__[prototypePollutionDomXss]=data:,alert(1); to trigger XSS via the prototypePollutionDomXss parameter.

    Server-side (via /api/email/sendSupportEmail)

    A URI parsing error allows injecting properties into the response object. For example, adding __proto__[status]=222 to the query string will result in the status parameter being set in the final JSON response.

  4. Understand MCP (Model Context Protocol) vulnerabilities

    stable

    The application exposes an MCP HTTP endpoint at /api/mcp that implements the JSON-RPC 2.0 protocol for AI agent tool calling. This endpoint is subject to several security vulnerabilities across its exposed tools and resources, including:

    • SQL Injection: via get_count tool.
    • Sensitive Data Exposure: get_config returns database credentials and API keys.
    • Server-Side Template Injection (SSTI): via render tool using the doT engine.
    • Local File Inclusion (LFI): resources/read accepts file:// URIs.
    • Remote Content Relay: resources/read accepts http:// and https:// URIs.
    • Server-Side JavaScript Injection: via process_numbers tool.
    • XML External Entity (XXE): via get_metadata tool.
    • Broken Access Control: via search_users tool.
    • Prototype Pollution: via update_user tool.
    • OS Command Injection: via spawn_process tool.
    • Session Management Issues: Including predictable session IDs, lack of immediate invalidation on DELETE /api/mcp, and the use of Mcp-Session-Id as a self-sufficient bearer credential.
  5. Exploit CSRF and Misconfigured CORS

    stable

    The application is vulnerable to Cross-Site Request Forgery (CSRF) because forms lack anti-CSRF tokens. Additionally, it has a misconfigured CORS policy that returns Access-Control-Allow-Origin: * for all requests.

    Testing targets:

    • Email subscription forms: Use these to test CSRF/CORS.
    • Add testimonial form: Available to authenticated users; use this to test authenticated CSRF.
  6. How MCP sessions work in BrokenCrystals

    stable

    Model Context Protocol (MCP) sessions in BrokenCrystals are independent of the standard API authentication flow. To use MCP tools or resources, you must follow this lifecycle:

    1. Initialize: Call the initialize method via POST /api/mcp first. This returns an Mcp-Session-Id.
    2. Session Persistence: Every subsequent non-initialize MCP request must include the Mcp-Session-Id in the request headers.
      • Missing Mcp-Session-Id results in an HTTP 400 error.
      • Unknown, expired, or terminated IDs result in an HTTP 404 error.
    3. Authentication:
      • You can initialize a guest session (unauthenticated).
      • You can initialize an authenticated session by providing an Authorization: Bearer <jwt> header to the initialize call. Authenticated sessions grant access to admin-only tools like get_config and spawn_process.
    4. Termination: Sessions can be scheduled for termination using DELETE /api/mcp with the Mcp-Session-Id. Note that the session is invalidated 5 minutes after the request, not immediately.

    Configuration: The default session TTL is 1800000 ms (30 minutes), controlled by the MCP_SESSION_TTL_MS environment variable.

    # Example: Initializing a guest MCP session
    BASE='https://brokencrystals.com'
    INIT=$(curl -i -s "${BASE}/api/mcp" -X POST \
      -H 'Content-Type: application/json' \
      -d '{"jsonrpc":"2.0","method":"initialize","id":1}')
    
    # Extracting the session ID
    MCP_SESSION_ID=$(echo "$INIT" | awk -F': ' 'tolower($1)=="mcp-session-id"{print $2}' | tr -d '\r')
  7. Exploit Hidden Upload XSS and File Upload

    stable

    The /hidden-upload endpoint is vulnerable to both XSS and unvalidated file uploads:

    1. XSS: Setting a filename to an HTML payload (e.g., <img src=x onerror=alert(1)>) results in the filename being injected into the DOM without sanitization.
    2. File Upload: Users can upload any image, including crafted SVGs, to /api/hidden-upload. The backend stores them in uploads/hidden and returns them as data URLs without content validation.
  8. Get started with the BrokenCrystals React Client

    stable

    Follow these steps to set up a local development environment for the client application:

    1. Clone the repository:
      git clone https://github.com/NeuraLegion/brokencrystals
    2. Navigate to the project directory:
      cd brokencrystals
    3. Install dependencies (using the client prefix):
      npm ci --prefix client
    4. Run the server application (refer to the repository's main README for server setup).
    5. Run the client in development mode:
      npm run start --prefix client
    git clone https://github.com/NeuraLegion/brokencrystals
    cd brokencrystals
    npm ci --prefix client
    npm run start --prefix client
  9. Build and run Broken Crystals with Docker

    stable

    To set up a local development environment including the application, Postgres DB, and MailCatcher, use Docker Compose with the local configuration file.

    Start the environment:

    docker compose --file=compose.local.yml up -d

    Rebuild and restart containers: If you make changes and need to rebuild the application and recreate containers, use:

    docker compose --file=compose.local.yml up -d --build --force-recreate
  10. Initialize an MCP session and retrieve configuration

    stable

    To interact with the Model Context Protocol (MCP) API, you must first initialize a session using the initialize method. This returns an mcp-session-id header which must be included in subsequent requests via the Mcp-Session-Id header. Once initialized, you can call the get_config tool to retrieve system configuration such as AWS bucket URLs, SQL connection strings, and API keys.

    # 1. Initialize the session
    ADMIN_INIT=$(curl -i -s "${BASE}/api/mcp" -X POST \
           -H 'Content-Type: application/json' \
           -H "Authorization: ${ADMIN_AUTH}" \
           -d '{"jsonrpc":"2.0","method":"initialize","id":3}')
    
    # 2. Extract the session ID
    ADMIN_MCP_SESSION_ID=$(echo "$ADMIN_INIT" | awk -F': ' 'tolower($1)=="mcp-session-id"{print $2}' | tr -d '\r')
    
    # 3. Call get_config tool
    curl "${BASE}/api/mcp" -X POST \
           -H 'Content-Type: application/json' \
           -H "Mcp-Session-Id: ${ADMIN_MCP_SESSION_ID}" \
           -d '{
             "jsonrpc": "2.0",
             "method": "tools/call",
             "params": {
               "name": "get_config",
                "arguments": {}
              },
             "id": 4
           }'