T09 · Insecure Skill Coding Practices
- Location
src/avenir_web/agent.py:164- Finding
Output Directory Traversal Through Unsanitized Task IDs
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This appears to be a legitimate web-automation skill, but it needs review because it can browse arbitrary URLs, send page screenshots to an LLM, and has verified safety weaknesses.
Install only in a contained environment with network egress controls and a non-sensitive browser session. Do not point it at private dashboards, localhost/internal services, authenticated accounts, or pages containing secrets unless you are comfortable sending screenshots and page-derived text to the configured LLM provider and retaining them in local artifacts. Update vulnerable dependencies and fix URL allowlisting, task_id path validation, logging redaction, and the os.system copy path before broader use.
src/avenir_web/agent.py:164Output Directory Traversal Through Unsanitized Task IDs
src/avenir_web/managers/action_execution_manager.py:284Unrestricted Browser Navigation Enables Internal Resource Access and External Screenshot Disclosure
src/avenir_web/runtime/browser.py:119Shell Command Injection in Configuration File Copy Helper
litellm==1.35.32 is explicitly flagged as a known vulnerable version with multiple advisories, including arbitrary file deletion and local file read issues. In an agent skill context, a vulnerable LLM integration library is particularly dangerous because it may process attacker-controlled inputs, credentials, files, and remote requests.
lxml==4.9.3 is identified as a known vulnerable pinned version with XXE-related risk. In a skill that may parse HTML or XML from external sources, XXE can enable file disclosure, SSRF, or interaction with internal resources if parser settings are unsafe.
This code sends screenshot contents to an external LLM API for GUI grounding without any visible per-use disclosure, consent check, or domain-based restriction. Because screenshots may include far more than the target element, the feature can silently export confidential page contents to a third party.
The function passes attacker-controllable values through a shell by building a command string for os.system("cp ..."). If config or save_file contains shell metacharacters, spaces, or command substitutions, this can lead to command injection or unintended file operations; even without metacharacters, naive joining is unsafe and brittle.
config_without_key["api_keys"]["openrouter_api_key"] = "Your API key here"
toml.dump(config_without_key, f)
else:
os.system(" ".join(["cp", str(config), str(save_file)]))
The project pins LiteLLM to version 1.35.32, and the scanner reports numerous published advisories affecting that exact release line. Because this package brokers LLM requests and may handle prompts, secrets, and remote API interactions in a web-agent context, a vulnerable version can materially expand attack surface and expose sensitive data or enable remote abuse depending on the advisory details.
The project pins lxml to 4.9.3, and the scanner reports advisories for XXE-prone default parser behavior affecting that version family. In a web agent that may process remote HTML/XML content, parser-level issues are more dangerous because attacker-controlled documents could trigger file disclosure, SSRF, or related parsing attacks if unsafe XML features are used.
The skill explicitly states that screenshots and page metadata are sent to the main model, but it does not require user notice, consent, or data minimization before doing so. Because web pages may contain sensitive account data, personal information, or internal content, this can cause unintended disclosure to an external model-processing component during normal use.
python-dotenv==1.0.1 is reported as a known vulnerable version, including a symlink-following arbitrary file overwrite issue in set_key. If the skill manipulates .env files or runs with elevated filesystem permissions, this can lead to configuration tampering or overwriting sensitive files.
The script captures a screenshot of an arbitrary webpage and submits that image, along with page metadata and a user-supplied question, to a model without any user-facing notice, consent check, or sensitivity guard. This can expose confidential on-screen data such as personal information, internal dashboards, tokens, or proprietary content to downstream model infrastructure, especially because the target URL is fully user-controlled.
The stop() logic persists llm_records.json containing model names, prompts, outputs, and referenced image paths, and those prompts are built from task text, prior actions, and page-derived context. This is sensitive retention because it can preserve proprietary instructions, browsing-derived data, and pointers to screenshots long after task completion.
The agent writes screenshots to disk routinely and can also save DOM HTML, accessibility trees, traces, and result files under task-specific directories. These artifacts may capture sensitive on-screen data, session state, internal page structure, or regulated information, and this file does not show any consent, minimization, or retention controls around that collection.
The ground_element path base64-encodes screenshots and sends them, together with user instructions, to an external LLM endpoint via litellm.acompletion. Browser screenshots can contain credentials, personal data, internal documents, or other sensitive page content, so this creates a real data-exfiltration channel outside the local trust boundary.
The SAY action records free-form text as "Chain of Thought" in logs, which may capture sensitive reasoning, user data, credentials, or internal prompts that should not be persisted. Explicitly labeling and storing chain-of-thought is especially risky because such content can contain more detail than necessary for observability and may leak protected internal context.
No manifest is available, so the skill's intended scope is unknown. This file implements direct URL navigation through GOTO, allowing the agent to browse arbitrary pages, which is a materially powerful capability that is not justified by any stated purpose in the provided context.
The TYPE handler logs the exact user-supplied value with self.logger.info(f"Typed '{value}'"), which can expose secrets such as passwords, tokens, PII, or form contents to logs. Log sinks are often broadly accessible and retained for long periods, so this creates an unnecessary secondary disclosure channel for sensitive input.
The code logs pred_value directly during action execution, and this value may contain secrets or sensitive user input such as passwords, tokens, personal data, or form contents. Those logs can persist in log files, observability systems, or error pipelines and be accessed by operators or attackers with log access, causing sensitive data exposure beyond the original browser session.
The prompt layer explicitly forbids GOTO navigation, but both parse_tool_call and validate_parsed_action still recognize and permit GOTO. This creates a policy-enforcement gap where an LLM or adversarial prompt can emit a disallowed navigation action that downstream code will accept, potentially enabling off-task or off-domain browsing despite the stated restrictions.
The select-failure warning tells the agent to try clicking to open a dropdown, directly conflicting with earlier instructions that elements must use the 'select' action and must not be opened via click. Contradictory guidance weakens policy reliability and can cause the model to fall back to less constrained interaction patterns, increasing the chance of unintended UI actions or bypass of intended safeguards.
The runner reads configured credentials and writes them into process environment variables for downstream use. While this may be functionally necessary, the file provides no confirmation prompt, user-facing log, or explanatory warning comment/docstring about handling sensitive credentials.
The browser context unconditionally sets the Accept-Language header to en-us, which imposes a specific language/locale on all requests. This is a natural-language policy concern because the file does not offer user choice or document a justified region-specific constraint.
The docstring says config is a dictionary and describes serialization behavior, but the implementation also accepts arbitrary non-dictionary input and copies it via a shell command. This mismatch can cause callers or reviewers to assume only safe serialization occurs, hiding the more dangerous execution path and increasing the likelihood of unsafe untrusted input reaching it.
This code records full LLM inputs and outputs, including prompts, model responses, task IDs, image paths, and potentially image-derived content sent to an external provider. Although large base64 image strings are truncated for storage, sensitive prompt text and response data are still retained in a global in-memory log without any evident consent, warning, minimization, or access controls, creating a privacy and data-handling risk.
This code forwards raw action descriptions to an external LLM engine for summarization without any visible redaction, consent, or policy enforcement at this boundary. Action descriptions in an agent system can contain sensitive user inputs, page contents, secrets, or internal workflow data, so transmitting them off-component can create a confidentiality leak even if the feature is intended for convenience.
The history update path sends both the prior accumulated summary and new action details to the LLM, which increases the amount of potentially sensitive context exposed to the model provider or downstream logging systems. Because summaries may already contain condensed sensitive information, repeatedly retransmitting them amplifies data exposure and retention risk.
The code builds an LLM prompt from page-derived form metadata and the user task, then sends it to engine.generate with no evidence of consent, minimization, redaction, or locality guarantees. Because form descriptions and current values may contain sensitive data from the active webpage, this can leak private or regulated information to an external model service during ordinary browser automation.
No suspicious patterns detected.