Back to skill

Security audit

SF Civic Digest

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed San Francisco civic digest that fetches public government, civic, and news data, with some local-state and privacy cautions but no evidence of deception or exfiltration.

Install only if you are comfortable with a skill that reads a local civic preference profile, fetches many public web sources, and keeps local JSON archives/state files. Avoid putting exact home/work addresses or sensitive people-of-interest notes in USER.md unless needed, run it without elevated privileges, and prefer installing dependencies from a pinned/isolated environment.

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
scripts/sf_planning_commission.py:303
Finding

Predictable Shared Temporary File Allows Symlink-Based File Overwrite

Content
View full analysis
/path/to/a/file/writable/by/the/victim ``` 3. The victim invokes `sf_planning_commission.py`, or the weekly aggregator invokes it as a child process. 4. The sc ...[truncated 893 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
scripts/sfmta_hearings.py:132
Finding

Unpinned Runtime Dependency Installation Guidance Creates Supply-Chain Risk

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • 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 (103)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The description presents a civic/government activity tracker focused on official meetings, hearings, legislation, planning notices, and district events across several SF government sources. The code does something materially different: it fetches SF 311 service request records from one Socrata endpoint, groups them by service category, flags unusually high volumes, and summarizes neighborhood quality-of-life issues by supervisorial district. This is SF-specific and district-related, but the primary purpose, dataset, and outputs do not match the declared behavior. The mismatch is substantial rather than a minor implementation variation.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The description claims a broad San Francisco civic monitoring skill covering multiple city agencies, committees, planning notices, and district events from several SF-specific sources. The code instead is narrowly focused on BART Board of Directors meetings via the BART Legistar API (webapi.legistar.com/v1/bart/Events). It classifies BART-related bodies, outputs upcoming/recent meetings, and stores an archive locally. None of the declared SF government entities, filtering features, or additional data sources are implemented in this code chunk. This is a clear material mismatch in both purpose and accessed resources.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared description presents a broad SF civic monitoring skill spanning many agencies, committees, and data sources. This code chunk instead implements a specific scraper for upcoming SF Board of Appeals hearings. That is a materially different scope and primary purpose from the declared functionality, and Board of Appeals is not included in the description’s listed coverage. While there is some overlap with SF-specific hearing tracking and district filtering, the actual code is much narrower and accesses only api.sf.gov in this chunk. Therefore the description does not accurately represent what this code actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The code's primary purpose is a building permit tracker for a supervisor district, using the Socrata building permits dataset at data.sfgov.org/resource/i98e-djp9.json. It does not fetch agendas, recaps, legislation, committee activity, public hearings, planning notices, or district events from the declared systems (SF Legistar, sfmta.com, sfplanning.org, api.sf.gov). While building permits may be tangentially related to neighborhood development, this script is materially narrower and different from the declared civic/government activity tracker. Therefore the description does not accurately represent the code chunk's actual behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The mismatch is substantial. The declared description is focused on official San Francisco government activity and land-use/planning monitoring from municipal sources. The code instead collects activist/community action events from Mobilize.us and Indybay, labels them as protests/rallies/canvasses, estimates event scale, and archives them. The primary purpose, data sources, and output domain are materially different from the declaration. Although both are SF-related civic information, this is not a close implementation of the described government-activity tracker.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The description overstates the implemented scope. The script clearly fetches meeting calendars and meeting details only from sfgov.legistar.com, parses agenda items/actions, filters them by configured keywords and district context, and outputs daily/weekly digests. It does include some broader body-name matching such as Planning Commission in priority bodies, but only insofar as those appear in Legistar. There is no code here for sfmta.com, sfplanning.org, api.sf.gov, or Socrata scraping, nor for SF.gov district events. So the declared description is not an accurate representation of this supplied code chunk's actual behavior. The local state/archive JSON writing is an extra implementation capability, though supporting rather than primary.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The code's primary purpose is materially different from the declared description. Rather than aggregating general SF civic/government activity such as agendas, committee hearings, planning notices, and district events from Legistar, SFMTA, SF Planning, and SF.gov, this script focuses on Ethics Commission content: RSS notices from sfethics.org and Socrata datasets about lobbyist contacts and campaign contributions. While it does include district-based filtering and keyword cross-referencing that superficially overlap with the declared neighborhood/topic tracking concept, the core behavior is ethics/lobbying oversight, not broad City Hall and development tracking. This is a substantial 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 is about an SF civic/government activity tracker focused on meetings, hearings, legislation, project notices, and district events from multiple municipal sources. The provided code is instead a specialized eviction notice tracker for the SF Rent Board dataset. Its primary function is to query eviction filings, classify eviction reasons, compute trends against a prior period, flag Ellis Act and owner move-in displacement signals, summarize by neighborhood, and save results to a local archive file. While both are SF-specific and district-oriented, the code’s core purpose, data source, and outputs are materially different from the declared civic agenda/hearing tracker.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description presents a broad SF civic activity tracker covering agendas, hearings, legislation, planning notices, and district events across several websites/APIs. The code instead implements a specialized housing development pipeline tracker for SF Planning project records. It queries only two Socrata endpoints, identifies streamlined approval pathways (AB 2011, SB 35, SB 423, density bonus, etc.), filters by supervisorial district via parcel lookup, tracks watchlist matches, archives records, and detects status changes. While there is some thematic overlap with planning/development, the actual primary purpose is materially narrower and different from the declared multi-source civic/government activity tracker.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The description says this skill tracks San Francisco city government activity, hearings, legislation, planning notices, and district events from official civic and government data sources. The code instead is an RSS news aggregator for six media outlets. While both are SF-related and it includes a limited district keyword tagging feature, the primary purpose, data sources, and outputs are materially different. The code does not fetch from the declared official sources, does not track government agendas or hearings directly, and instead collects journalism articles. 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 code’s primary purpose is a Mission Local news monitor, not an SF government activity tracker. It accesses a single RSS feed at missionlocal.org and filters articles for civic relevance, especially District 5 topics. It does not fetch from Legistar, sfmta.com, sfplanning.org, api.sf.gov, or Socrata, and it does not retrieve official agendas, hearing recaps, planning notices, legislation, or district events. While there is thematic overlap in that some Mission Local stories may concern SF civic matters, the actual behavior is materially different from the declared description and relies on an inconsistent resource type (news outlet RSS versus official government sources).

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The code is SF-specific and does match a subset of the description: it tracks upcoming hearings for Planning Commission, Historic Preservation Commission, and Zoning Administrator hearings from sfplanning.org, including district-based filtering. However, the declared purpose describes a much broader multi-source civic tracker spanning numerous city bodies and sources (Legistar, SFMTA, SF.gov API, Socrata, district events, project notices). This code chunk does not implement those capabilities or access those resources. Its actual primary purpose is much narrower than declared, 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
97% confidence
Finding

This is a material description-behavior mismatch. The description promises a comprehensive SF civic tracker spanning many agencies and data sources, but the supplied code chunk is narrowly scoped to Recreation and Park Commission meetings on one Granicus page. It fetches meeting listings and agendas, classifies agenda items using keywords (including some district-config-driven terms), and maintains local archive/state files. While the district/keyword logic is somewhat aligned with the general idea of localized relevance, the primary purpose, covered entities, and accessed resources are substantially narrower than declared. 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
98% confidence
Finding

There is a clear material mismatch. The declared description presents a multi-source, citywide civic monitoring skill covering numerous agencies, hearings, legislation, development notices, and geographic/topic filtering. The supplied code instead implements a single-purpose Rent Board Commission meeting scraper. Its network access is limited to sf.gov/api.sf.gov endpoints and related rent-board pages, and its outputs are meeting schedules, agenda PDFs, attachments, and a rent-increase reference. This is not merely a partial implementation detail; the code’s primary purpose, covered entities, and sources differ substantially from the declared behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

There is a material description/behavior mismatch. The declared description presents a comprehensive SF civic activity tracker spanning multiple agencies, committees, planning/hearing bodies, and data sources, with geographic/topic filtering. The supplied code instead has a distinct and much narrower primary purpose: monitoring SFCTA meetings and agenda items from sfcta.org. While SFCTA is SF civic/government-related, it is not one of the declared bodies/sources, and the broad multi-source, multi-agency, neighborhood/district-filtered functionality described is absent from this code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The description claims a comprehensive SF-specific civic monitoring skill spanning numerous agencies, data sources, and geographic/topic filters. The supplied code chunk is much narrower: it scrapes only SFMTA Board of Directors meeting pages from sfmta.com, extracts agenda items, classifies them into high/medium/low relevance for transit riders, and maintains local seen/archive state. While SFMTA Engineering Public Hearings are mentioned in the declared scope, this code is not for those hearings and does not cover the broader declared functionality. This is a material description-behavior mismatch because the implemented capability is only a small subset of the claimed skill.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description presents a broad San Francisco city-government monitoring skill covering legislative, planning, transportation, and district event sources with geographic/topic filtering. The supplied code instead is narrowly focused on SFUSD Board of Education meeting schedules. It fetches a public Google Sheet, falls back to BoardDocs scraping, links to Granicus video archives, generates projected dates when parsing fails, and stores a local archive. While SFUSD is San Francisco-related, it is not the set of city-government entities named in the description, and the implementation lacks the declared multi-source civic coverage and filtering features. This is a material 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 promises an SF civic/government activity tracker focused on legislative bodies, public hearings, planning/zoning matters, and official civic feeds from Legistar, SFMTA, SF Planning, SF.gov API, and Socrata. The supplied code does something materially different: it scrapes upcoming volunteer cleanup events from Refuse Refuse SF and SF Public Works, filters them by district/neighborhood, and prints or emits JSON. While both are SF-local and district-filterable, that overlap is superficial. The primary purpose, data sources, and outputs are substantially different from the declared behavior, so this is a clear mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description presents a comprehensive SF civic monitoring skill spanning many sources and government bodies. The supplied code chunk is much narrower: a single scraper for upcoming meetings from api.sf.gov's sf.Meeting endpoint. It parses meeting metadata, agenda titles, locations, comment email, and related PDFs, then optionally filters by district via configured neighborhood/street keywords. Importantly, it explicitly excludes some entities named in the description (e.g., Board of Supervisors, Planning Commission, SFMTA board) because they are supposedly handled by other scripts not shown here. Therefore, this code does not itself implement much of the declared multi-source, multi-body functionality. There is also a minor undeclared capability: maintaining a local JSON archive of fetched meetings. Overall, the description materially overstates scope relative to this code chunk.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 25)May include surrounding context.

md
**Note:** `sf_weekly_digest.py` makes ~22 network calls sequentially and can take 2-3 minutes. For a quick test, try a single script first: `python3 "$SKILL_DIR

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 65)May include surrounding context.

md
**Note:** `sf_weekly_digest.py` makes ~22 network calls sequentially and can take 2-3 minutes. For a quick test, try a single script first: `python3 "$SKILL_DIR

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 73)May include surrounding context.

md
| `sf_311.py` | 311 service requests by district | Socrata REST | Spike detection. Query two 7-day windows for trend comparison. |

Missing User Warnings

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

This profile solicits sensitive personal and location data, including neighborhood, streets, addresses to watch, transportation habits, and people of interest, but provides no privacy notice, purpose limitation, consent language, or handling safeguards. In combination, these fields can reveal a user's home/work patterns, routines, and interests, increasing harm from misuse, overcollection, or accidental disclosure.

Content

No source excerpt is available for this finding.

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · USER.md (reported line 30)May include surrounding context.

md
## What I Care About

<!-- What issues matter to you? Housing, transit, public safety, tenant protections, parks?
     The more specific you are, the better the editorial judgment. Examples:

     **Housing:** Pro-building. Track stalled projects and anything that constrains the pipeline.

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · USER.md (reported line 54)May include surrounding context.

md
## How I Want Reports Written

**Depth:** <!-- e.g., "Technical — don't simplify" or "Plain language, no jargon" -->

**Format:** <!-- e.g., "Narrative with through-lines" or "Bullet points, scannable" -->

Static analysis

No suspicious patterns detected.