Back to skill

Security audit

AgentZero

Security checks for vulnerabilities and agentic risk

Overview

This mostly behaves like a local real estate tracker, but it needs review because it under-discloses powerful browser automation and risky startup behavior.

Review this before installing. Use it only in a trusted local workspace, inspect the startup scripts first, avoid running the browser fallback unless you accept the sandbox/profile risks, and rotate or protect any Anthropic and Gmail credentials used with it. Prefer fixing host validation, removing broad pkill/kill -9 behavior, disabling persistent no-sandbox browser automation, and sanitizing logs before routine use.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (5)

T09 · Insecure Skill Coding Practices

Error
Location
backend/src/parsers/mod.rs:154
Finding

Substring-Based Host Validation Enables Server-Side Request Forgery

Content
View full analysis
Option { if url.contains("redfin.") { Some(ListingSite::Redfin) } else if url.contains("rew.ca") { Some(ListingSite::Rew) } else if url.contains("zillow.com") { Some(ListingSite::Zillow) } else if url.contains("realtor.ca") { Some(ListingSite::Realtor) } else { None } } ``` The result is treated as a validated listing URL: ```rust pub(crate) fn parse_listing_url(input: &str) -> Option { let cleaned = strip_url_query(input); let u = Url::parse(&cleaned).ok()?; match u.scheme() { "http" | "https" => { let site = crate::parsers::ListingSite::from_url(&cleaned)?; Some(ListingUrl { url: u, site }) } _ => None, } } ``` The accepted URL is then requested by the backend: ```rust async fn fetch_html_direct(client: &Client, url: &Url) -> Result { let mut headers = HeaderMap::new(); // Header construction omitted. let resp = client.get(url.as_str()).headers(headers).send().await?; resp.error_for_status_ref()?; resp.text().await } ``` ### Technical Analysis The code checks whether the complete URL string contains a trusted-site substring. It does not compare the parsed hostname to an explicit allowlist. Consequently, attacker-controlled hosts such as the following can pass validation: ```text https://redfin.attacker.example/listing https://rew.ca.attacker.example/listing https://zillow.com.attacker.example/listing ``` An attacker-controlled accepted hostname can resolve to a loopback, private, link-local, or othe ...[truncated 1601 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
backend/src/agent/review.rs:129
Finding

Untrusted Listing Metadata Can Inject Instructions into Automatic AI Triage

Content
View full analysis
String { let mut lines = vec![ "You are triaging a real estate listing against a set of search profiles.".to_string(), "Decide which profile best matches, or skip if none fit.".to_string(), String::new(), "Listing:".to_string(), format!(" Title: {}", p.title), format!(" Price: {price} {currency}"), format!(" Address: {address}"), format!( " Beds/Baths: {} / {}", p.bedrooms .map(|v| v.to_string()) .unwrap_or_else(|| "—".to_string()), p.bathrooms .map(|v| v.to_string()) .unwrap_or_else(|| "—".to_string()) ), String::new(), "Search profiles:".to_string(), ]; for profile in profiles { lines.push(format!( " [{}] {}: {}", profile.id, profile.title, ...[truncated 2585 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
backend/src/lib.rs:158
Finding

Backend Logs Reveal a Significant Fragment of the Anthropic API Key

Content
View full analysis
"$LOG_FILE" 2>&1 & ``` ### Technical Analysis The masking operation exposes up to the first seven and last four characters of the API key. Revealing eleven characters is unnecessary for confirming configuration and can identify or correlate a credential across logs and systems. The normal startup workflow writes this fragment to `/tmp/agent_zero_backend.log`. The script does not explicitly set restrictive permissions before creating that file. Actual exposure depends on the user's `umask`, existing file ownership, and operating-system protections. Logging `DATABASE_URL` may also expose sensitive information if an operator configures a non-SQLite URL containing embedded credentials, although the documented default is a local SQLite path. ### Attack Path 1. A user starts the backend thr ...[truncated 906 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/run_backend.sh:14
Finding

Backend Startup Script Force-Kills Unrelated Processes

Content
View full analysis
/dev/null || true pkill -f "target/release/agent_zero_backend" 2>/dev/null || true pkill -f "cargo run --release" 2>/dev/null || true ``` ### Technical Analysis The script does not verify that the process using the configured port belongs to AgentZero. It sends `SIGKILL` to every process returned by `lsof` for that port. The final `pkill` expression is especially broad: any process whose command line contains `cargo run --release` can be terminated, even when it belongs to another project. `SIGKILL` prevents graceful shutdown, cleanup, and transaction completion. The behavior exceeds the minimum privilege necessary to start this backend. A safe launcher should manage only the process instance it created. ### Attack Path 1. A user follows the documented Skill installation or restart instructions. 2. Another application is listening on the selected port, or an unrelated Rust project is running through `cargo run --release`. 3. `run_backend.sh` enumerates or pattern-matches that process. 4. The script sends `SIGKILL` or otherwise terminates it without confirming its identity. 5. The unrelated service stops immediately and may lose in-memory state or incomplete work. A malicious local user may also intentionally occupy the configured port with a victim process or influence environment configuration to increase disruption, subject to operating-system process ownership restrictions. ### Impact Assessment The script can cause denial of service to processes owned by the invoking user. Potential consequences include: - Termination of unrelated development or production services. - Loss of unsaved work and in-memory state. - Interr ...[truncated 296 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
backend/src/fetching/fetch.rs:122
Finding

Listing Fetch Fallback Launches Browser Automation with Disabled Sandbox and Persistent State

Content
View full analysis
Result { let home = std::env::var("HOME").unwrap_or_else(|_| ".".to_string()); let profile_dir = std::path::PathBuf::from(home).join(".agent-zero-chrome-profile"); let _ = std::fs::create_dir_all(&profile_dir); let profile_dir = std::fs::canonicalize(&profile_dir).unwrap_or(profile_dir); let mut builder = BrowserConfig::builder() .disable_default_args() .no_sandbox() .window_size(1920, 1080) .user_data_dir(profile_dir) .arg("--disable-blink-features=AutomationControlled") .arg("--disable-features=IsolateOrigins,site-per-process") .arg("--disable-infobars") .arg("--disable-dev-shm-usage") .arg("--no-first-run") .arg("--disable-gpu") .arg("--lang=en-US,en") .arg("--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36") .with_head(); let macos_chrome = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"; if std::path::Path::new(macos_chrome).exists() { builder = builder.chrome_executable(macos_chrome); } let config = builder .build() .map_err(|e| format!("Chrome config error: {e}"))?; ``` The fallback also automates Safari: ```rust let output = tokio::process::Command::new("osascript") .arg("-e") .arg(&script) .output() .await .map_err(|e| format!("osascript failed: {e}"))?; ``` The Chrome session receives stealth modifications: ```rust const STEALTH_JS: &str = r#" Object.defineProperty(navigator, 'webdriver' ...[truncated 2403 chars]
Remediation
View remediation
Vulnerability Patterns
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (149)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents a full operational skill for interacting with a local real estate backend and related workflows. The supplied code chunk does not implement any of those behaviors or access any of the mentioned resources. It is only a generated type definition for change-history field names. This is a materially different purpose from the declared skill behavior, so the description does not accurately represent this code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Based on the supplied code chunk alone, the declared description is not accurately represented. The code does not implement any of the described functionality; it merely exposes a review module. While this could be a small fragment of a larger system, the task is to compare the provided description against the provided code chunk, and this chunk’s apparent purpose is materially different or at least insufficiently aligned with the stated real-estate-agent workflow.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The core declared behavior around adding property listings by URL and the special agent-suggest triage flow is accurately represented by the code. The blocked-host behavior for Zillow/Realtor.ca stubs also matches, and no dangerous unrelated resource access appears in this snippet. However, the description claims a broader skill surface than this code chunk actually provides: refreshing listings, listing search profiles/scenarios, daily email scanning with himalaya and Gmail/openclaw, and mandatory workspace log writing are not implemented here. In addition, the code contains several substantive behaviors not mentioned in the description, such as saving raw HTML snapshots, downloading/caching images, storing open houses, and computing mortgage defaults. Because the evaluation asks whether the declared description accurately represents what the supplied code chunk actually does, this is a mismatch: the description is materially broader and omits notable implemented side effects.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description focuses on adding listings by URL, refreshing listings, listing search profiles/scenarios, and a daily email scan workflow. The supplied code chunk instead serves a different set of backend endpoints centered on modifying existing listing metadata and reading audit history. Those are substantive capabilities not mentioned in the description. While all functionality is within the broader real-estate tracker domain, the primary purpose of this code is listing detail maintenance and history retrieval, not adding/refreshing/listing profiles or email scanning. Additionally, the code explicitly validates editable URLs for Redfin, Realtor, REW, and Zillow, which does not align cleanly with the description's statement that Zillow and Realtor.ca are blocked when adding listings. Therefore the description does not accurately represent this code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description focuses on listing ingestion, refresh, search profile/scenario listing, and email-driven URL extraction/logging workflows. The supplied code instead implements image cache deletion for an existing listing. This is a materially different capability and primary purpose from the declared functions, and it accesses storage layers (object store, image cache DB records, filesystem directories) not mentioned in the description. This is not merely a supporting detail of adding or refreshing listings; it is a separate destructive media-management endpoint.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description focuses on adding listings by URL, refreshing existing listings, enumerating search profiles/scenarios, and a separate email-driven ingestion workflow. This code chunk instead exposes GET/DELETE endpoints for saved listings themselves: list all listings, fetch one listing, and delete a listing plus cached images. Deletion is a materially significant capability absent from the description, so this is a mismatch. While listing properties is related to the broader domain, the described operations and the implemented ones do not align closely enough for this chunk to be considered accurately represented.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This code chunk does not implement the declared functions such as adding property listings by URL, refreshing listings, listing search profiles/scenarios, triaging with Claude, reading email alerts, opening Gmail, or logging summaries. Instead, it exposes CRUD-like API behavior for open house records tied to listings. That is a materially different capability area within the same broader real estate system, and it is not represented in the declared description. Therefore this is a description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

The declared description focuses on operational workflows around the AgentZero listing tracker: adding or refreshing listings, listing profiles/scenarios, triaging added listings, scanning emails, and logging summaries. The supplied code instead implements a lower-level parsing endpoint that accepts a URL, fetches the page, extracts structured/raw fields, and explicitly does not save to the database. While parsing listing pages could be a supporting component of the broader system, this specific code chunk's primary behavior is materially different from the declared skill behavior and includes an undeclared parse API capability.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The declared description mentions listing search profiles/scenarios, adding/refreshing property listings, triaging listings, email scanning, and logging. This code chunk is specifically a search-profile management API and exposes several mutating capabilities not reflected in the description: create, update, reorder, and delete search profiles, plus get-by-id. Listing search profiles is consistent with the description, but the broader implemented behavior is materially different and extends beyond the declared purpose. There is no evidence here of listing URL ingestion, refresh, email scanning, browser use, or log writing.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description presents a skill for operating a real-estate listing tracker and related workflows. The actual code chunk is just a minimal Rust main function that delegates to a CLI strip subcommand. Based on the code provided, its primary purpose does not match the declared real-estate backend interaction workflow. Because the code appears to implement a different command entirely and shows none of the described behaviors or resource access patterns, this is a clear description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Based on the provided chunk alone, the code does not substantiate the declared purpose. It merely defines a Rust module (strip) under a CLI namespace, which is a structural/code-organization action rather than the described real estate tracker integration workflow. While this could be a tiny fragment of a larger system, the task is to compare the supplied code chunk to the declared description, and this chunk does not reflect the stated functionality or resources.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

This code does not interact with the AgentZero backend at http://localhost:8000, does not add or refresh listings, does not list search profiles/scenarios, does not perform email scanning, and does not log summaries to agent_zero_logs. Instead, it is a standalone CLI tool for preprocessing parser fixture HTML files on disk. Its primary purpose, accessed resources, and triggers differ materially from the declared skill description, so this is a clear mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description presents this skill as a client for a local real-estate backend plus optional email-scan workflow and workspace logging. This code chunk does not implement backend interaction, email access, or logging. Instead, it performs remote web fetching with multiple fallbacks, including browser automation and anti-bot evasion techniques. The strongest mismatch is that the description says Zillow and Realtor.ca are blocked and only stub-saved, while this code explicitly recognizes those hosts as bot-protected targets and attempts to fetch them using Safari/Chrome automation. Browser automation and stealth injection are material undeclared capabilities, not merely internal details, because they access different resources and use significantly different behavior than a simple localhost backend client.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

This code chunk’s primary purpose is financial calculation for real-estate-related costs, not operating the AgentZero listing tracker workflows described. The module contains only pure helper functions for mortgage and monthly-cost computation and a small result struct. It does not access localhost:8000, parse listing URLs, triage listings, read email, open a browser, or write logs. Because the actual behavior is materially different from the declared purpose, this is a clear description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description focuses on high-level listing-management operations against an AgentZero real estate backend, plus optional email/Gmail-based daily scan workflows and markdown logging. This code does not implement adding listings by URL, refreshing listings, listing search profiles/scenarios, triaging listings, scanning email, opening a browser, or writing action summaries to logs. Instead, it performs a distinct backend subsystem task: caching listing images, deduplicating them by SHA-256 and perceptual hash, and storing them in an object store/local filesystem while updating database cache rows. These are materially different capabilities and resource accesses from the declared purpose, so this is a clear mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

This code snippet appears to be an internal image-handling module declaration, not an implementation of the declared real-estate workflow. Its primary behavior is organizing and exposing image caching/path utilities. That is materially different from the declared purpose of interacting with a listing tracker backend, processing listing URLs, triaging listings, scanning email alerts, and logging actions. While this could be a supporting submodule elsewhere in a larger system, based on the supplied chunk alone the behavior does not accurately represent the declared skill description.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description focuses on interacting with the AgentZero backend for listing ingestion, refresh, search profile/scenario listing, email scanning, and activity logging. The actual code chunk does none of those user-facing workflows. Instead, it is a narrow utility module for image path/URL construction and local image directory handling. This is not merely a supporting implementation detail of the described actions as presented here; the code’s primary purpose is materially different from the declared skill behavior, and it does not implement or expose the described backend interactions, email access, or logging behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

The description broadly matches a local AgentZero real-estate backend at localhost:8000 and does mention adding listings, refreshing listings, listing search profiles, and agent-suggest triage. However, this code chunk exposes substantially more functionality than declared: full search-profile CRUD and reorder operations, listing detail/notes/search-profile patching, agent review submission and triggering, open-house endpoints, history retrieval, image deletion, and static serving of cached images. It also explicitly depends on ANTHROPIC_API_KEY at startup, which is not called out as an operational requirement in the declared permissions/description beyond mentioning Claude triage. Conversely, important declared behaviors are not present in this chunk: no evidence of the Daily Email Scan workflow using himalaya or openclaw/Gmail, and no evidence of logging summaries to agent_zero_logs/YYYY-MM-DD.md after actions. Because there are both undeclared exposed capabilities and declared behaviors absent from the supplied code, this is a meaningful description/behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This code chunk appears to be a small supporting model file for image handling, not an implementation of the declared skill behavior. The declared purpose centers on operational workflows and external interactions with the AgentZero backend, email, browser, and logging. The actual code neither performs those actions nor reflects those primary capabilities; it only defines serialization structs for images. Because the supplied code chunk's behavior is materially different from the declared purpose, this should be flagged as a mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The code shown is a structural module file for model definitions, not an implementation of the described skill behavior. While model types like Property and SearchProfile are related to the real estate domain, the chunk does not actually perform the declared actions or access the declared resources. This is a material description-to-code mismatch because the description promises operational capabilities far beyond what this code implements.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This code chunk is a narrow model definition for open house data structures used by the backend. The declared purpose presents the skill as an operational interface for managing real estate listings, scanning email alerts, and writing logs. None of those capabilities appear in the supplied code. Because the actual code has a materially different immediate purpose—defining open house entities rather than implementing the described workflows—the description does not accurately represent this chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

The declared description is for an operational skill that talks to a local real-estate tracking backend, performs listing-add/refresh/list actions, possibly scans email alerts, and writes log files. The supplied code chunk does none of that. It is a schema/model layer: enums for SourceStatus and ListingStatus, property record structs, SQLx encode/decode support, and a UserDetails struct representing editable fields for PATCH /api/listings/:id/details. While these models are relevant to the same application domain, they do not implement the described behaviors or resource access. The code also exposes a broader/editing-oriented data capability not mentioned in the description. Therefore the description does not accurately represent what this code chunk actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared description presents a high-level operational skill centered on interacting with a localhost AgentZero backend and related workflows. The supplied code chunk instead is a lower-level parsing module. That difference alone could be acceptable if the code were clearly a supporting component of the same skill. However, there is a material contradiction: the description says Zillow and Realtor.ca are blocked / stub-saved, while this code explicitly recognizes zillow.com and realtor.ca URLs and dispatches to dedicated parsers for both. This indicates capabilities inconsistent with the declared behavior. Additionally, the chunk contains none of the described API interaction, email scanning, browser use, triage orchestration, or logging behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This is a clear description/behavior mismatch. The declared purpose describes a higher-level skill that talks to a localhost AgentZero backend and says Realtor.ca is blocked rather than parsed. The code chunk instead implements detailed Realtor.ca scraping/parsing functionality, including extracting listing metadata, coordinates, images, and open house events from Realtor.ca HTML. While parser code could be a backend implementation detail, the key issue is that it directly contradicts the declared behavior around Realtor.ca support: the description says Realtor.ca URLs are blocked and only stubs are saved, but this code is specifically designed to parse Realtor.ca listings into rich structured records. The rest of the declared workflow capabilities are also absent from this code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared description presents an operational skill that interacts with a localhost backend, processes listing URLs, may access email/browser workflows, and logs summaries. The supplied code does none of that. Instead, it is internal Rust test-support code for parser fixtures and data conversion. It does not call the backend, add or refresh listings, list profiles/scenarios, access IMAP/Gmail, or write logs. This is a materially different purpose rather than a mere supporting implementation detail for the declared workflow, so the description does not accurately represent the code chunk.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.