Back to skill

Security audit

Blacksnow

Security checks for vulnerabilities and agentic risk

Overview

BlackSnow has a coherent risk-intelligence purpose, but its implementation has material Review concerns around insecure live-data fetching, unbounded local retention, and broad webhook delivery.

Install only if you are comfortable with a sandboxed, experimental risk-intelligence tool that stores harvested records locally and can send generated primitives to configured webhooks. Use it with verified TLS restored, webhook destinations restricted to approved HTTPS endpoints, mock sources clearly disabled or labeled, and local retention/deletion controls added before relying on outputs for business or financial decisions.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/harvester_extended.py:35
Finding

TLS Certificate and Hostname Verification Disabled for External Data Sources

Content
View full analysis
Optional[bytes]: """Safely fetch URL with SSL handling.""" try: ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE hdrs = {"User-Agent": "BlackSnow/0.1 (Risk Intelligence)"} if headers: hdrs.update(headers) req = urllib.request.Request(url, headers=hdrs) with urllib.request.urlopen(req, timeout=timeout, context=ctx) as response: return response.read() ``` ```python # scripts/harvester_extended.py:181-192 try: req = urllib.request.Request( self.BASE_URL, data=json.dumps(payload).encode(), headers={"Content-Type": "application/json", "User-Agent": "BlackSnow/0.1"} ) ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE with urllib.request.urlopen(req, timeout=15, context=ctx) as response: ``` ### Technical Analysis The code creates a standard TLS context and then explicitly disables both certificate verification and hostname validation. As a result, the client cannot authenticate the remote government data services it contacts. Any certificate, including a self-signed certificate controlled by an attacker, will be accepted. A network-positioned attacker can ther ...[truncated 1804 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/webhook.py:121
Finding

Unrestricted Webhook Destination Permits SSRF and Plaintext Disclosure

Content
View full analysis
1: webhook_url = sys.argv[1] results = run_full_pipeline(webhook_url=webhook_url, verbose=True) ``` ```python # scripts/webhook.py:121-128 req = urllib.request.Request( self.config.url, data=payload_bytes, headers=headers, method="POST" ) with urllib.request.urlopen(req, timeout=30) as response: ``` ```python # scripts/webhook.py:167-169 def add_endpoint(self, url: str, tier: str = "operator", secret: str = None): """Register a webhook endpoint.""" self.endpoints.append(WebhookConfig(url=url, tier=tier, secret=secret)) ``` ### Technical Analysis The webhook URL is accepted directly from a command-line argument or configuration file and used as an outbound request destination. The implementation does not enforce: - An HTTPS-only scheme. - A trusted hostname allowlist. - An approved port list. - DNS and resolved-IP validation. - Rejection of loopback, private, link-local, multicast, or reserved addresses. - Rejection of cloud instance metadata addresses. - Safe redirect handling and destination revalidation. This permits a party that controls the webhook argument or configuration to make the host send POST requests to destinations reachable from the host's network context. Examples include localhost services, private network services, and link-local infrastructure. The webhook sends packaged risk primitives and operational metadata rather than credentials or raw harvested records. Webhook delivery is declared functionality, so this is not covert exfiltration. Nevertheless, allowing arbitrary destinations exceeds the minimum network authority required for a production webhook integr ...[truncated 1822 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/memory.py:63
Finding

Unfiltered Raw Records Are Persisted Without Enforced Retention or Restrictive Permissions

Content
View full analysis
int: """Store raw signals to daily file.""" today = datetime.now(timezone.utc).strftime("%Y-%m-%d") filepath = SIGNALS_DIR / f"signals_{today}.jsonl" stored = 0 with open(filepath, 'a') as f: for sig in signals: record = asdict(sig) if hasattr(sig, '__dataclass_fields__') else sig record["_stored_at"] = datetime.now(timezone.utc).isoformat() f.write(json.dumps(record, default=str) + "\n") stored += 1 ``` The declared retention and privacy constraints are: ```yaml # manifest.yaml:99-105 memory: type: workspace-longitudinal retention_policy: raw_signals_days: 180 aggregated_vectors_days: 1095 purpose: - drift_detection - confidence_calibration - backtesting ``` ```yaml # manifest.yaml:107-112 constraints: legal: - gdpr_compliant - no_personal_data_storage - no_market_manipulation_intent ``` ### Technical Analysis The persistence layer writes the complete serialized source record, including `raw_text`, title, URL, and metadata, to daily JSONL files. It performs no field minimization, PII ...[truncated 2310 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (18)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The described behavior omits external webhook delivery, endpoint loading from config, HMAC signing, and batch fan-out to multiple destinations. Undocumented outbound transmission is dangerous because the skill handles potentially sensitive market-relevant signals; hidden egress can exfiltrate data to arbitrary endpoints, amplify distribution beyond intended recipients, and bypass operator review.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The described behavior omits external webhook delivery, endpoint loading from config, HMAC signing, and batch fan-out to multiple destinations. Undocumented outbound transmission is dangerous because the skill handles potentially sensitive market-relevant signals; hidden egress can exfiltrate data to arbitrary endpoints, amplify distribution beyond intended recipients, and bypass operator review.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The described behavior omits external webhook delivery, endpoint loading from config, HMAC signing, and batch fan-out to multiple destinations. Undocumented outbound transmission is dangerous because the skill handles potentially sensitive market-relevant signals; hidden egress can exfiltrate data to arbitrary endpoints, amplify distribution beyond intended recipients, and bypass operator review.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill metadata omits any explicit tool scope or permissions while the underlying implementation reportedly has file read, file write, and network capabilities. That creates a trust boundary problem: operators reviewing only SKILL.md would not know the skill can persist state, read local data, or send data off-host, increasing the chance of unintended data exposure or misuse.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The module docstring says the harvester 'Connects to real public data sources for ambient risk signals,' and the main flow announces 'live data collection.' In reality, only the Federal Register source is live; SAM.gov and NLRB data are returned from mock harvesters with fabricated static examples, which contradicts the documented behavior.

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 · scripts/harvester.py (reported line 24)May include surrounding context.

python
SOURCES = {
    "sam_gov": {
        "name": "SAM.gov Federal Opportunities",
        "url": "https://api.sam.gov/opportunities/v2/search",
        "type": "procurement",
        "requires_key": True
    },

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

TLS verification is explicitly disabled by setting check_hostname=False and verify_mode=ssl.CERT_NONE before fetching live Federal Register data. This allows man-in-the-middle attackers to intercept or modify supposedly trusted external content, which is especially dangerous here because the skill converts harvested signals into machine-readable risk inputs that could influence automated decisions or trading behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

TLS certificate validation and hostname checking are explicitly disabled in the shared fetch helper, so every HTTPS request using this path is vulnerable to man-in-the-middle interception or response tampering. Because this skill ingests external data and converts it into risk signals, an attacker controlling network traffic could inject false intelligence into multiple downstream sources.

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 · scripts/harvester_extended.py (reported line 163)May include surrounding context.

python
"""USASpending.gov - federal contract awards."""
    
    NAME = "USASpending.gov"
    BASE_URL = "https://api.usaspending.gov/api/v2/search/spending_by_award/"
    
    def harvest(self) -> List[RawSignal]:
        signals = []

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

The USASpending POST request also disables TLS verification, exposing both the query and the returned award data to interception or modification in transit. Even though the payload is not highly sensitive, tampered responses could poison the system's procurement risk signals and produce false conclusions or trades.

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 · scripts/harvester_extended.py (reported line 219)May include surrounding context.

python
"""DOT Safety recalls and investigations."""
    
    NAME = "DOT NHTSA"
    BASE_URL = "https://api.nhtsa.gov/recalls/recallsByDate"
    
    def harvest(self) -> List[RawSignal]:
        signals = []

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 · scripts/harvester_extended.py (reported line 227)May include surrounding context.

python
"""DOT Safety recalls and investigations."""
    
    NAME = "DOT NHTSA"
    BASE_URL = "https://api.nhtsa.gov/recalls/recallsByDate"
    
    def harvest(self) -> List[RawSignal]:
        signals = []

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 · scripts/harvester_extended.py (reported line 295)May include surrounding context.

python
"""EIA - Energy Information Administration data."""
    
    NAME = "EIA"
    BASE_URL = "https://api.eia.gov/v2/electricity/rto/daily-region-data/data/"
    
    def harvest(self) -> List[RawSignal]:
        # EIA requires API key, return mock for now

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The EIA harvester explicitly claims live/API-key-based handling but returns a fabricated risk signal instead of fetched source data. In a system producing machine-readable, tradable risk primitives, synthetic data presented as live intelligence can mislead downstream decisions, create false market signals, and undermine auditability and trust.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/memory.py (reported line 54)May include surrounding context.

python
}
    
    def _save_state(self):
        """Persist state to disk."""
        with open(STATE_FILE, 'w') as f:
            json.dump(self.state, f, indent=2, default=str)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The code persistently writes raw signals and vectors to JSONL files under the user's home directory without any disclosure, consent flow, minimization, or access-control hardening. Because this skill explicitly handles ambient risk signals and tradable risk primitives, stored records may contain sensitive operational, legal, or human-related intelligence that can be retained longer than users expect and exposed to other local users, malware, backups, or forensic review.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

Belief-state history is stored longitudinally on disk, creating a durable record of inferred trends over time without any user-facing notice or retention boundary beyond a per-vector history cap. In the context of a system designed to detect pre-news risk signals, these histories can reveal sensitive strategic assessments and behavioral patterns even if the original signals are not directly reviewed.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This code sends pipeline output to a user-supplied webhook URL, which is a network operation that can transmit harvested and derived data off-system. The only disclosure is a verbose print statement, so when verbose=False there is no confirmation, prompt, or user-facing warning before transmission.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.