Back to skill

Security audit

Flight Pricer

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it claims, but it handles a Duffel API key in an under-protected and overconfident way that users should review before installing.

Review this before installing if the Duffel API key has billing or account privileges. Prefer entering the key through a hidden prompt, environment variable, or credential store, and restrict ~/.config/flight-pricer/config.yaml to your user only. Install in an isolated virtual environment and consider pinning dependencies before use.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
flight_pricer.py:88
Finding

Duffel API Key Stored Without Enforced Restrictive Permissions

Content
View full analysis
``` ### Technical Analysis The configuration directory and credential file are created without explicitly enforcing restrictive permissions. Their effective permissions therefore depend on the operating system and the process umask. An existing configuration file also retains its previous permissions when overwritten. The implementation does not verify that the directory is restricted to the current user or that the file has mode `0600`. The API key is additionally accepted directly through `--api-key`. Command-line arguments may be retained in shell history and can be visible in process listings or process-inspection interfaces while the command is running. The documentation describes this mechanism as secure storage, but the implementation does not provide the permission controls necessary to support that claim. ### Attack Path 1. A victim runs `flight-pricer config set --api-key `. 2. The secret may be recorded in the victim's shell history or temporarily exposed through process arguments. 3. The program writes the secret to `~/.config/flight-pricer/config.yaml` without explicitly setting mode `0600`. 4. A local user or process with access to the h ...[truncated 674 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
pyproject.toml:1
Finding

Unpinned Third-Party Dependencies Permit Unreviewed Package Resolution

Content
View full analysis
=61.0"] build-backend = "setuptools.build_meta" [project] name = "flight-pricer" version = "1.0.0" authors = [ { name="J R", email="jrojas537@gmail.com" }, ] description = "A CLI for searching flight prices via the Duffel API." readme = "README.md" requires-python = ">=3.7" classifiers = [ "Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", ] dependencies = [ "click", "requests", "pyyaml", "tabulate", ] ``` `requirements.txt:1-4`: ```text click requests pyyaml tabulate ``` The documented installation command in `SKILL.md:24` resolves these dependencies dynamically: ```bash pip install -e flight-pricer/ ``` ### Technical Analysis The runtime dependencies have no version constraints, and the build dependency permits any `setuptools` release from version 61.0 onward. Installation therefore resolves whichever compatible releases are currently provided by the configured package index. This makes installations non-reproducible and prevents the project from guaranteeing that the installed artifacts are the versions that were reviewed or tested. If a dependency release, package-index account, configured mirror, or dependency-resolution path is compromised, malicious package code may enter the environment without any source-code change in this project. No evidence was found that the listed package names are currently malicious or typosquatted. The risk arises from unconstrained future resolution and the absence of integrity verification. ### Attack Path 1. An attacker compromises a dependency publisher, package-index account, or package mirror, or causes a malicious future release to be ...[truncated 918 chars]
Remediation
View remediation
\ --hash=sha256: requests== \ --hash=sha256: pyyaml== \ --hash=sha256: tabulate== \ --hash=sha256: ``` Exact versions and hashes should be generated from currently supported, reviewed releases rather than copied from an unverified source. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (14)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The README instructs users to pass the Duffel API key directly on the command line and states it will be stored locally, but it does not warn that command-line arguments may be exposed through shell history, process listings, logs, or agent telemetry. In an agent-integrated CLI context, this increases the chance that credentials are unintentionally captured or persisted in places outside the intended config file.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · flight_pricer.py (reported line 11)May include surrounding context.

python
CONFIG_DIR = os.path.expanduser("~/.config/flight-pricer")
CONFIG_FILE = os.path.join(CONFIG_DIR, "config.yaml")
API_BASE_URL = "https://api.duffel.com/air/offer_requests"

def get_api_key():
    """Loads the API key from the config file."""

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · flight_pricer.py (reported line 148)May include surrounding context.

python
click.echo("Searching for flights...")
    
    try:
        response = requests.post(API_BASE_URL, headers=headers, json=payload)
        response.raise_for_status()
        
        response_data = response.json()

Unverifiable Dependency: setuptools has 10 known advisory(ies) (CVE-2013-1633 (Setuptools vulnerable to Man-in-the-middle attacks); CVE-2025-47273 (setuptools has a path traversal vulnerability in PackageIndex.download that lead); CVE-2024-6345 (setuptools vulnerable to Command Injection via package URL) +7 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Unverifiable Dependency: click has 1 known advisory(ies) (CVE-2026-7246 (Pallets Click, versions 8.3.2 and below, contain a command injection vulnerabili)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Unverifiable Dependency: pyyaml has 8 known advisory(ies) (CVE-2019-20477 (Deserialization of Untrusted Data in PyYAML); CVE-2020-1747 (Improper Input Validation in PyYAML); CVE-2020-14343 (Improper Input Validation in PyYAML) +5 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

The dependency 'click' is unpinned, so installs may resolve to different versions over time. This weakens build reproducibility and can unintentionally introduce vulnerable or incompatible releases into the environment.

Content

Scanner excerpt · requirements.txt (reported line 1)May include surrounding context.

text
click
requests
pyyaml
tabulate

Unverifiable Dependency: click has 1 known advisory(ies) (CVE-2026-7246 (Pallets Click, versions 8.3.2 and below, contain a command injection vulnerabili)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
88% confidence
Finding

The manifest does not pin 'click', and advisories exist for some Click versions, so the environment could resolve to an affected release without visibility. In this file alone the exact affected version cannot be confirmed, but the absence of version constraints makes the risk real and unverifiable.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

The dependency 'requests' is unpinned, allowing future installs to pull different versions than originally tested. This creates supply-chain risk and makes it harder to ensure vulnerable releases are excluded.

Content

Scanner excerpt · requirements.txt (reported line 2)May include surrounding context.

text
click
requests
pyyaml
tabulate

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
93% confidence
Finding

The manifest leaves 'requests' unpinned despite numerous historical advisories, so an installation may pull a vulnerable version depending on resolution time and environment. Because Requests is commonly used for network access, vulnerable releases can expose sensitive data or weaken transport-related security assumptions.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

The dependency 'pyyaml' is unpinned, so the installed version may vary across environments and over time. Because PyYAML has had past security issues, leaving it unpinned increases the chance of resolving to an unsafe version.

Content

Scanner excerpt · requirements.txt (reported line 3)May include surrounding context.

text
click
requests
pyyaml
tabulate

Unverifiable Dependency: pyyaml has 8 known advisory(ies) (CVE-2019-20477 (Deserialization of Untrusted Data in PyYAML); CVE-2020-1747 (Improper Input Validation in PyYAML); CVE-2020-14343 (Improper Input Validation in PyYAML) +5 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The manifest does not constrain 'pyyaml', and PyYAML has a history of serious issues including unsafe deserialization-related flaws. If this skill processes untrusted YAML, an affected version could materially increase exploitation risk, and the unpinned requirement prevents verifying safety.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency 'tabulate' is unpinned, which reduces reproducibility and permits unreviewed version changes during installation. Even without a cited advisory here, unpinned dependencies increase supply-chain uncertainty.

Content

Scanner excerpt · requirements.txt (reported line 4)May include surrounding context.

text
click
requests
pyyaml
tabulate

Static analysis

No suspicious patterns detected.