HIGH api key exposurerocket

Api Key Exposure in Rocket

How Api Key Exposure Manifests in Rocket

Api Key Exposure in Rocket applications typically occurs through improper handling of authentication credentials in API endpoints. Rocket's flexible request handling can inadvertently expose API keys through several vectors that developers might overlook.

The most common manifestation involves API keys being logged in plaintext. When Rocket processes requests with API keys in headers or query parameters, developers might log entire request objects or use debug logging that captures sensitive headers. For example, a simple debug statement like println!("Request: {:?}", req) can expose API keys in production logs.

Query parameter exposure represents another significant risk. Rocket's query parameter extraction automatically parses URL parameters, and developers might accidentally expose API keys through error messages or logging. Consider this vulnerable endpoint:

#[get("/api/data?&&")]
fn get_data(api_key: String, param1: String, param2: String) -> Json<Response> {
    // API key now exists as a plain String in memory
    log::debug!("Processing request with api_key: {}", api_key);
    // ...
}

The API key is now stored as a plain String, logged in debug output, and potentially exposed through error messages if the function panics.

Middleware and request guards can also create exposure points. Rocket's FromRequest trait allows custom authentication, but improper implementation can lead to API key leakage. A naive implementation might look like:

struct ApiKey(String);

impl<'a, 'r> FromRequest<'a, 'r> for ApiKey {
    type Error = &'static str;

    fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
        match request.headers().get_one("x-api-key") {
            Some(key) if key.len() > 0 => Outcome::Success(ApiKey(key.to_string())),
            _ => Outcome::Failure((Status::Unauthorized, "Missing API key"))
        }
    }
}

#[get("/api/protected")]
fn protected_endpoint(key: ApiKey) -> Json<Response> {
    // API key accessible as key.0
    // If this endpoint errors, the API key might be exposed in error responses
}

The vulnerability here is that the API key is stored as a plain String and passed directly to the handler, making it accessible to any code that might log or expose it.

Environment variable mishandling also contributes to API key exposure. Developers might accidentally commit Rocket configuration files containing API keys, or use debug builds that print configuration values. Rocket's configuration system allows loading from various sources, and improper handling of these sources can lead to exposure.

Rocket-Specific Detection

Detecting API key exposure in Rocket applications requires a multi-faceted approach combining static analysis, runtime monitoring, and automated scanning.

Static analysis tools can identify vulnerable patterns in Rocket codebases. Look for these specific patterns:

# Search for API key handling patterns
rg -n "api_key|API_KEY|auth|Auth" --type rust
# Find query parameter extraction with sensitive names
rg -n "get_one.*api_key|get_one.*auth" --type rust
# Locate logging of request objects
rg -n "println.*request|debug.*request|log.*request" --type rust

Manual code review should focus on request guards and parameter extraction. Examine all FromRequest implementations and query parameter handlers for proper API key handling. Pay special attention to error handling paths where API keys might be inadvertently exposed.

Runtime monitoring can detect API key exposure through log analysis. Configure Rocket's logging to capture all request processing, then analyze logs for API key patterns:

# Monitor logs for API key patterns
journalctl -u rocket-app -f | grep -E "(api_key|API_KEY|auth_token|Auth-Token)"

# Check for sensitive data in error responses
curl -s http://localhost:8000/api/endpoint | grep -E "(api_key|API_KEY|auth_token)"

Automated scanning with middleBrick provides comprehensive API key exposure detection. middleBrick's black-box scanning approach tests your Rocket API endpoints without requiring source code access or credentials. The scanner examines:

  • Request headers for API key patterns
  • Query parameters containing authentication tokens
  • Response bodies for leaked credentials
  • Logging endpoints and debug interfaces
  • Configuration endpoints that might expose API keys

middleBrick's LLM/AI Security module specifically detects system prompt leakage patterns that might contain API keys, using 27 regex patterns to identify various prompt formats including ChatML, Llama 2, Mistral, and Alpaca formats.

To scan your Rocket API with middleBrick:

# Using the CLI tool
middlebrick scan https://your-rocket-api.com/api

# Using the npm package
npx middlebrick scan https://your-rocket-api.com/api

# Using the GitHub Action
- name: Scan Rocket API
  uses: middlebrick/middlebrick-action@v1
  with:
    api_url: https://your-rocket-api.com/api
    fail_below_score: 80

middleBrick's 12 security checks run in parallel and specifically test for authentication-related vulnerabilities, including API key exposure through various attack vectors. The scanner provides actionable findings with severity levels and remediation guidance tailored to your specific vulnerability.

Rocket-Specific Remediation

Remediating API key exposure in Rocket requires implementing secure handling patterns and leveraging Rocket's built-in security features. The goal is to ensure API keys are never exposed in logs, error messages, or response bodies.

The first step is implementing proper request guards that don't store API keys as plain Strings. Use Rocket's Secret type or custom secure wrappers:

use rocket::request::{FromRequest, Request};
use rocket::http::Status;
use rocket::outcome::Outcome;

struct SecureApiKey(Option<String>);

impl<'a, 'r> FromRequest<'a, 'r> for SecureApiKey {
    type Error = ();

    fn from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error> {
        let keys: Vec<_> = request.headers().get("x-api-key").collect();
        
        if keys.len() == 1 {
            // Store as Option to prevent accidental logging
            Outcome::Success(SecureApiKey(Some(keys[0].to_string())))
        } else {
            Outcome::Failure((Status::Unauthorized, ())) 
        }
    }
}

#[get("/api/protected")]
fn protected_endpoint(key: SecureApiKey) -> Json<Response> {
    // API key is wrapped and not directly accessible
    // Implement authorization logic without exposing the key
    if let SecureApiKey(Some(api_key)) = key {
        // Use api_key internally without logging or exposing
        validate_and_process(api_key)
    } else {
        Json(Response::error("Unauthorized"))
    }
}

fn validate_and_process(api_key: &str) -> Json<Response> {
    // Never log the API key
    // Implement proper validation without exposing credentials
    if is_valid_api_key(api_key) {
        Json(Response::success("Authorized"))
    } else {
        Json(Response::error("Invalid API key"))
    }
}

fn is_valid_api_key(key: &str) -> bool {
    // Implement secure validation without exposing the key
    // Example: compare against hashed values
    let stored_hash = get_stored_hash_for_key(key);
    verify_hash(key, stored_hash)
}

This implementation prevents accidental API key exposure by wrapping the key in a struct that doesn't implement Debug or other traits that might cause logging.

Configure Rocket's logging to exclude sensitive information. Create a custom logger that filters out API keys:

use log::{Level, Record};
use std::sync::Mutex;

struct ApiKeyFilterLogger;

impl log::Log for ApiKeyFilterLogger {
    fn enabled(&self, metadata: &log::Metadata) -> bool {
        metadata.level() <= Level::Debug
    }
    
    fn log(&self, record: &Record) {
        if self.enabled(record.metadata()) {
            let msg = record.args().to_string();
            // Filter out API key patterns
            if !msg.contains("api_key") && !msg.contains("API_KEY") {
                println!("[{}] {}", record.level(), msg);
            }
        }
    }
    
    fn flush(&self) {}
}

pub fn init_logger() {
    log::set_boxed_logger(Box::new(Mutex::new(ApiKeyFilterLogger))).unwrap();
    log::set_max_level(log::LevelFilter::Info);
}

Implement proper error handling that doesn't expose API keys in error messages. Use generic error responses:

#[derive(Serialize)]
struct ApiError {
    error: String,
    code: u16,
}

impl ApiError {
    fn unauthorized() -> Self {
        ApiError { 
            error: "Unauthorized".to_string(), 
            code: 401 
        }
    }
    
    fn invalid() -> Self {
        ApiError { 
            error: "Invalid request".to_string(), 
            code: 400 
        }
    }
}

#[catch(401)]
fn unauthorized_catcher() -> Json<ApiError> {
    Json(ApiError::unauthorized())
}

#[catch(400)]
fn bad_request_catcher() -> Json<ApiError> {
    Json(ApiError::invalid())
}

fn main() {
    rocket::ignite()
        .register(catchers![unauthorized_catcher, bad_request_catcher])
        .launch();
}

Configure Rocket to use environment variables for API keys without exposing them in configuration files. Use Rocket's configuration system securely:

use rocket::config::{Config, Environment};

fn build_config() -> Config {
    let api_key = std::env::var("API_KEY").expect("API_KEY must be set");
    
    // Never log the API key
    let config = Config::build(Environment::Production)
        .address("0.0.0.0")
        .port(8000)
        .finalize()
        .unwrap();
        
    config
}

fn main() {
    let config = build_config();
    rocket::custom(config)
        .mount("/api", routes![protected_endpoint])
        .launch();
}

Finally, integrate continuous security scanning into your development workflow using middleBrick's GitHub Action to automatically scan your Rocket API endpoints before deployment:

name: Security Scan

on: [pull_request]

jobs:
  security-scan:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Scan Rocket API
      uses: middlebrick/middlebrick-action@v1
      with:
        api_url: ${{ secrets.ROCKET_API_URL }}
        fail_below_score: 85
        token: ${{ secrets.MIDDLEBRICK_TOKEN }}
    - name: Report results
      run: |
        echo "API security scan completed"

This comprehensive approach ensures API keys are properly handled throughout your Rocket application's lifecycle, from development through production deployment.

Frequently Asked Questions

How can I test my Rocket API for API key exposure without exposing credentials?
Use middleBrick's black-box scanning approach which tests your API endpoints without requiring any credentials or source code access. The scanner examines request/response patterns, headers, and error messages to detect API key exposure patterns. Simply provide your Rocket API URL and middleBrick will test for vulnerabilities including API key leakage through logs, error responses, and query parameters.
What's the difference between API key exposure in Rocket vs other frameworks?
Rocket's Rust-based architecture provides memory safety benefits that reduce certain types of API key exposure, but its flexible request handling and custom request guards can create unique exposure points. Unlike interpreted frameworks, Rocket's compile-time checks catch some vulnerabilities, but developers must still be careful with logging, error handling, and request parameter extraction. Rocket's strong typing helps prevent accidental exposure, but improper implementation of request guards or query parameter handling can still lead to API key leakage.