Skip to main content

An AI agent interrogation framework for identifying attack surface.

Project description

Agent Interrogator

Agent Interrogator Logo

Systematically discover and map AI agent attack surface for security research

PyPI version Python 3.9+ License: Apache 2.0


What is Agent Interrogator?

Agent Interrogator is a Python library designed for security researchers to systematically discover and analyze AI agent attack surface through automated interrogation. It uses iterative discovery cycles to map an agent's available tools (functions).

Why Use Agent Interrogator?

  • 🔍 Attack Surface Discovery: Automatically discovers agent capabilities and supporting tools without requiring documentation
  • 🛡️ Security Research: Purpose-built for vulnerability assessment and prompt injection testing
  • 📊 Structured Output: Generates structured profiles perfect for integration with other security tools
  • 🔄 Iterative Analysis: Uses smart prompt adaptation to uncover hidden or complex capabilities
  • 🚀 Flexible Integrations: Works with any agent via customizable callback functions

Perfect For:

  • Security researchers testing AI agents for vulnerabilities
  • Red teams conducting agent penetration testing
  • Security teams auditing agent functionality

Quick Start

Installation

pip install agent-interrogator

Basic Usage

Here's a minimal example that interrogates an agent:

import asyncio
from agent_interrogator import AgentInterrogator, InterrogationConfig, LLMConfig, ModelProvider

# Configure the interrogator
config = InterrogationConfig(
    llm=LLMConfig(
        provider=ModelProvider.OPENAI,
        model_name="gpt-4.1",
        api_key="your-openai-api-key"
    ),
    max_iterations=5
)

# Define how to interact with your target agent
async def my_agent_callback(prompt: str) -> str:
    """
    This function defines how to send prompts to your target agent.
    Replace this with your actual agent interaction logic.
    """
    # Example: HTTP API call to your agent
    # response = await call_your_agent_api(prompt)
    # return response.text
    
    # For demo purposes, return a mock response
    return "I can help with web searches, file operations, and calculations."

# Run the interrogation
async def main():
    interrogator = AgentInterrogator(config, my_agent_callback)
    profile = await interrogator.interrogate()
    
    # View discovered capabilities
    print(f"Discovered {len(profile.capabilities)} capabilities:")
    for capability in profile.capabilities:
        print(f"  - {capability.name}: {capability.description}")
        for f in capability.functions:
            print(f"    Function Name: {f.name}")
            print(f"    Function Parameters: {f.parameters}")
            print(f"    Function Return Type: {f.return_type}")

if __name__ == "__main__":
    asyncio.run(main())

Expected Output

Discovered 3 capabilities:
  - web_search: Search the internet for information
    Function Name: search_web
    Function Parameters: [ { "name": "query", "type": "string", "description": "The search query", "required": true }, { "name": "max_results", "type": "integer", "description": "Maximum number of results", "required": false, "default": 5 } ]
    Function Return Types: list[SearchResult]
...

Installation

Standard Installation

pip install agent-interrogator

Development Installation

For contributors or advanced users who want to modify the code:

git clone https://github.com/qwordsmith/agent-interrogator.git
cd agent-interrogator
pip install -e .[dev]

Requirements

  • Python: 3.9 or higher
  • OpenAI API Key: For using GPT models (optional, can use Ollama or any OpenAI-compatible endpoint instead)
  • Dependencies: Automatically installed with pip

Configuration

Agent Interrogator supports OpenAI, a local Ollama daemon, or any OpenAI-compatible endpoint (vLLM, LM Studio, LocalAI, etc.) for analyzing agent responses:

OpenAI Configuration

from agent_interrogator import InterrogationConfig, LLMConfig, ModelProvider, OutputMode

config = InterrogationConfig(
    llm=LLMConfig(
        provider=ModelProvider.OPENAI,
        model_name="gpt-4.1",
        api_key="your-openai-api-key"
    ),
    max_iterations=5,  # Maximum discovery cycles
    output_mode=OutputMode.STANDARD  # QUIET, STANDARD, or VERBOSE
)

Optional: pass openai=OpenAIConfig(timeout=180.0) on LLMConfig if you want to override the OpenAI client's default request timeout. Provider parity with OllamaConfig and OpenAICompatibleConfig, which both expose timeout.

Newer OpenAI reasoning models (gpt-5.x, o1, o3, o4): auto-detected by name prefix — the library omits its default temperature=0.1 for these so they fall back to the only value they accept (1.0). No config changes needed. To force a temperature anyway (or override for any model), pass model_kwargs={"temperature": ...} on LLMConfig.

Ollama Configuration (local models)

from agent_interrogator import OllamaConfig

config = InterrogationConfig(
    llm=LLMConfig(
        provider=ModelProvider.OLLAMA,
        model_name="llama3.2:latest",  # Any model pulled into your Ollama daemon
        ollama=OllamaConfig(
            host="http://localhost:11434",
            timeout=120.0,
            options={"temperature": 0.1, "top_p": 0.9},
            keep_alive="5m",
        )
    ),
    max_iterations=5,
    output_mode=OutputMode.VERBOSE
)

OpenAI-Compatible Endpoint Configuration

Use this for any server that exposes an OpenAI-shaped Chat Completions API (vLLM, LM Studio, LocalAI, custom gateways, etc.).

from agent_interrogator import OpenAICompatibleConfig

config = InterrogationConfig(
    llm=LLMConfig(
        provider=ModelProvider.OPENAI_COMPATIBLE,
        model_name="local-model",
        openai_compatible=OpenAICompatibleConfig(
            base_url="http://localhost:8000/v1",
            api_key="not-required",  # Some endpoints ignore this
            timeout=120.0,
        )
    ),
    max_iterations=5,
    output_mode=OutputMode.STANDARD
)

Output Modes

  • QUIET: No terminal output (ideal for automated scripts)
  • STANDARD: Shows progress and results (default)
  • VERBOSE: Detailed logging including prompts and responses (useful for debugging)

Implementing Callbacks

The callback function is how Agent Interrogator communicates with your target agent. It must be an async function that takes a prompt string and returns the agent's response.

Callback Interface

from typing import Awaitable, Callable

# Your callback must match this signature
AgentCallback = Callable[[str], Awaitable[str]]

HTTP API Example

Here's an example for an agent exposed via an HTTP API:

import aiohttp
from typing import Optional

class HTTPAgentCallback:
    def __init__(self, endpoint: str, api_key: Optional[str] = None):
        self.endpoint = endpoint
        self.headers = {}
        if api_key:
            self.headers["Authorization"] = f"Bearer {api_key}"
        self.session: Optional[aiohttp.ClientSession] = None
    
    async def __call__(self, prompt: str) -> str:
        if not self.session:
            self.session = aiohttp.ClientSession()
        
        async with self.session.post(
            self.endpoint,
            json={"message": prompt, "stream": False},
            headers=self.headers
        ) as response:
            if response.status != 200:
                raise Exception(f"Agent API error: {response.status}")
            
            result = await response.json()
            return result["response"]
    
    async def cleanup(self):
        """Optional cleanup method"""
        if self.session:
            await self.session.close()
            self.session = None

# Usage
callback = HTTPAgentCallback(
    endpoint="https://your-agent-api.com/chat",
    api_key="your-agent-api-key"
)

interrogator = AgentInterrogator(config, callback)
profile = await interrogator.interrogate()

More Examples

For additional callback implementations (WebSocket, Playwright browser automation, process-based agents, etc.), see the examples/callbacks.py file.


Understanding Results

Agent Interrogator produces a structured AgentProfile containing all discovered capabilities and functions. This data is specifically designed for security research and tool integration.

Profile Structure

# Access the profile data
profile = await interrogator.interrogate()

# Iterate through capabilities
for capability in profile.capabilities:
    print(f"Capability: {capability.name}  [{capability.node_id}]")
    print(f"Description: {capability.description}")

    for function in capability.functions:
        print(f"  Function: {function.name}  [{function.node_id}]")
        print(f"  Description: {function.description}")
        print(f"  Return Type: {function.return_type}")

        for param in function.parameters:
            print(f"    Parameter: {param.name}")
            print(f"    Type: {param.type}")
            print(f"    Required: {param.required}")
            print(f"    Default: {param.default}")

Identity & Deduplication

Each Capability and Function carries a stable, content-addressed node_id (cap_<sha1[:12]> / fn_<sha1[:12]>) derived from a normalized form of its name and — for functions — its parameter signature and return type.

The interrogation loop UPSERTs by node_id: when the target re-describes a tool across cycles (often with slightly different wording), the entries are merged into a single record rather than appended as duplicates. Field-level merge keeps the richer description, unions parameter lists by (name, type), and treats required=True as sticky. The loop also short-circuits once a cycle produces no new or updated entries.

Stable node_ids mean profiles can be diffed across runs (or across agent versions) by joining on identity, and lay the groundwork for a forthcoming graph-backed storage mode analogous to BloodHound's MERGE-by-ObjectIdentifier ingestion.

Security Research Applications

The structured data enables:

  • Attack Surface Mapping: Complete inventory of agent capabilities
  • Fuzzing Target Generation: Automated payload creation for each function
  • Prompt Injection Testing: Parameter-aware injection attempts
  • Capability Monitoring: Track changes between agent versions
  • Agent Auditing: Verify agents operate within expected bounds

Development

Running Tests

# Install development dependencies
pip install -e .[dev]

# Run the test suite
pytest tests/

# Run with coverage
pytest tests/ --cov=agent_interrogator

Code Quality

# Format code
black src/ tests/
isort src/ tests/

# Type checking
mypy src/agent_interrogator/

# Linting
flake8 src/ tests/

Project Structure

agent-interrogator/
├── src/agent_interrogator/    # Main package
│   ├── __init__.py           # Public API
│   ├── interrogator.py       # Core interrogation loop (UPSERT by node_id)
│   ├── config.py             # Configuration models
│   ├── llm.py                # LLM provider interfaces
│   ├── merge.py              # Field-level UPSERT helpers
│   ├── models.py             # Data models (AgentProfile, etc.)
│   ├── output.py             # Terminal output management
│   └── prompt_templates.py   # LLM prompts
├── examples/                 # Usage examples
├── tests/                    # Test suite

Contributing

Contributions are welcome!

How to Contribute

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Add tests for your changes
  4. Ensure all tests pass (pytest tests/)
  5. Format your code (black src/ tests/)
  6. Submit a pull request

Areas for Contribution

  • Callback implementations for different agent types
  • Recursive interrogation of agents to agent communication
    • Agents made available to target agent via A2A
    • Agents made available to target agent via MCP
  • Performance optimizations for large-scale agent scanning
  • Guardrail bypass capabilities
  • Integration examples with security tools
  • Additional LLM provider support
  • Mechanisms to improve agent profile output quality
  • Documentation improvements

License

This project is licensed under the Apache License, Version 2.0 - see the LICENSE file for details.

Support

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

agent_interrogator-0.2.0.tar.gz (39.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agent_interrogator-0.2.0-py3-none-any.whl (28.7 kB view details)

Uploaded Python 3

File details

Details for the file agent_interrogator-0.2.0.tar.gz.

File metadata

  • Download URL: agent_interrogator-0.2.0.tar.gz
  • Upload date:
  • Size: 39.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for agent_interrogator-0.2.0.tar.gz
Algorithm Hash digest
SHA256 321b4ba04380d5ff928cb65c6237696c1d7166ef47d5c1458a30b6b969fb5519
MD5 f51bcd5a99c90781eeac53370f48b43f
BLAKE2b-256 ace7ebd0428e46d2ddd775ca03ee7c22ca06ecf408bd03c86bce2c8febf35645

See more details on using hashes here.

File details

Details for the file agent_interrogator-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for agent_interrogator-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 770313355674e2855392465e7cba0234a381887aa429be52c5e0aee9b0471b03
MD5 e847d2403bba9f41b1ab6f114d33d2cd
BLAKE2b-256 87e26494108b6d579ecaf9ff88cc3e8deef3f90eceae8ab7768be703fbe8367b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page