Back to skill

Security audit

Fulcra Morning Briefing

Security checks for vulnerabilities and agentic risk

Overview

The skill is purpose-aligned for a morning briefing, but it handles sensitive health and calendar data through broadly scoped shell-based workflows with supply-chain, storage, and persistence risks users should review first.

Install only if you are comfortable giving the workflow access to Fulcra health, activity, calendar, and location-derived context. Prefer pinning the Fulcra CLI version, running it as an unprivileged user, avoiding the `FULCRA_CLI_COMMAND` override unless you fully control it, using a private 0700 directory instead of `/tmp/briefing.json`, and being aware that weather lookup sends the configured location to wttr.in.

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)

T08 · Insecure Dependencies

Warning
Location
collect_briefing_data.py:44
Finding
Unpinned Third-Party CLI Package Is Retrieved and Executed## Vulnerability Details **File Location**: `collect_briefing_data.py:44-53`; related invocation guidance appears in `SKILL.md:41`, `SKILL.md:52`, `SKILL.md:269-272`, and `README.md:18` **Vulnerability Type**: T08: Insecure Dependencies **Risk Level**: Medium ### Vulnerable Code ```python def run_fulcra_json(*args: str) -> Any: command = os.environ.get("FULCRA_CLI_COMMAND", "uv tool run fulcra-api").split() result = subprocess.run( [*command, *args], capture_output=True, text=True, timeout=60, check=False, ) if result.returncode != 0: message = (result.stderr or result.stdout or "Fulcra CLI command failed").strip() raise RuntimeError(message) return parse_json_output(result.stdout) ``` Related documented commands include: ```bash uv tool run fulcra-api auth login ``` ```bash uv tool run fulcra-api --help uv tool run fulcra-api auth login --help uv tool run fulcra-api data-updates "14 hours" uv tool run fulcra-api calendar-events --help ``` ### Technical Analysis The default command uses `uv tool run fulcra-api` without an exact package version, lockfile, or integrity verification. Depending on the local `uv` cache and resolution behavior, this can retrieve and execute the currently available package release when the collector or authentication flow runs. The Skill legitimately needs a Fulcra client, but resolving a mutable package at execution time is not the minimum-risk way to provide that dependency. Authentication and all sensitive data queries consequently depend on package contents that can change after the Skill itself has been reviewed. This is a supply-chain weakness rather than evidence that the current Fulcra package is malicious. The audited project contains no embedded malicious payload and does not itself read `~/.config/fulcra/credentials.json`. Nevertheless, code executed as part of the CLI runs wi ...[truncated 1365 chars]
Remediation
## Remediation Suggestions 1. Pin `fulcra-api` to a reviewed exact version rather than resolving an unconstrained release: ```bash uv tool run fulcra-api==REVIEWED_VERSION ``` 2. Prefer installing the dependency once in a dedicated virtual environment and invoking its fixed executable path. 3. Commit a lockfile with cryptographic hashes when the packaging workflow supports it. 4. Verify package provenance, publisher identity, and release signatures or hashes before upgrades. 5. Test and review each dependency update before changing the pinned version. 6. Run the collector as an unprivileged, dedicated user with access only to the data and directories required for the briefing. 7. Document the supported version so authentication and data-query behavior cannot silently change between runs.

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:277
Finding
Sensitive Health and Calendar Data Is Directed to a Predictable Shared Temporary File## Vulnerability Details **File Location**: `SKILL.md:277-280`; sensitive output is assembled and emitted by `collect_briefing_data.py:264-275` **Vulnerability Type**: T09: Insecure Skill Coding Practices **Risk Level**: Medium ### Vulnerable Code The documented scheduled-task example writes the complete result to a fixed path in the shared temporary directory: ```bash # Example: 7:30 AM ET daily 30 7 * * * cd /path/to/workspace && python3 skills/fulcra-morning-briefing/collect_briefing_data.py > /tmp/briefing.json ``` The redirected JSON contains the following sensitive categories: ```python briefing = { "ok": True, "generated_at": datetime.now(timezone.utc).isoformat(), "freshness": summarize_data_updates(f"{args.lookback} hours"), "sleep": get_sleep(api, args.lookback), "heart_rate": get_metric_summary(api, "HeartRate", 10), "hrv": get_metric_summary(api, "HeartRateVariabilitySDNN", 12), "steps": get_steps(api), "calendar": get_calendar(api), "weather": get_weather(args.location), } print(json.dumps(briefing, indent=2, default=str)) ``` ### Technical Analysis `/tmp/briefing.json` is a predictable pathname in a directory shared by local users and processes. Shell redirection creates the file according to the cron process's current `umask`; the documentation does not require mode `0600`, a private parent directory, atomic creation, ownership validation, or cleanup. On systems with a common `022` umask, a newly created regular file can be readable by other local users. The data includes intimate biometric measurements and calendar event titles, times, and locations. Repeated scheduled execution also leaves persistent data at a stable, discoverable location. Predictable temporary paths can additionally expose file-replacement or symbolic-link risks. Whether symbolic-link exploitation succeeds depends on operating-system protections, ownership, and directory settin ...[truncated 1503 chars]
Remediation
## Remediation Suggestions 1. Do not store the output in a global temporary directory. Use a user-private state directory, for example: ```bash install -d -m 700 "${XDG_STATE_HOME:-$HOME/.local/state}/fulcra" umask 077 python3 skills/fulcra-morning-briefing/collect_briefing_data.py \ > "${XDG_STATE_HOME:-$HOME/.local/state}/fulcra/briefing.json" ``` 2. Create output files with mode `0600` and ensure the parent directory is owned by the scheduled-task user with mode `0700`. 3. Use atomic file creation and replacement. Create a secure temporary file inside the private directory, write and flush it, then rename it to the final path. 4. Reject symbolic links and validate ownership before replacing an existing file. In programmatic implementations, use secure open flags such as `O_NOFOLLOW`, `O_CREAT`, and appropriate exclusive-creation semantics where supported. 5. Define a short retention period and securely delete obsolete briefing files. 6. Prefer passing JSON directly to the trusted agent through a pipe or protected IPC mechanism so no persistent plaintext copy is required. 7. Ensure scheduled tasks run as an unprivileged user and never as root.
Vulnerability Patterns
  • 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
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
Findings (24)

Credential Access

High
Category
Privilege Escalation
Content
## Quick Start

1. Install prerequisites: `uv` and `jq`
2. Authorize: `uv tool run fulcra-api auth login` (one-time, the user approves; the CLI can create the account if needed). Fulcra accounts include 5 GB of storage free forever and do not require an API key. For remote agents, surface only the printed device URL and code to the intended user in chat through the active trusted user channel; never send access tokens or credential files.
3. Optional: set `FULCRA_CONTEXT_SCRIPTS=/path/to/local/service/scripts` only if your host provides a local `fulcra_data_service.py`; the published `fulcra-context` skill is docs-first and does not ship helper scripts.
4. Collect data: `python3 collect_briefing_data.py --location "Your+City"`
5. Agent reads the JSON and composes a briefing using the tone rules in SKILL.md
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
## Quick Start

1. Install prerequisites: `uv` and `jq`
2. Authorize: `uv tool run fulcra-api auth login` (one-time, the user approves; the CLI can create the account if needed). Fulcra accounts include 5 GB of storage free forever and do not require an API key. For remote agents, surface only the printed device URL and code to the intended user in chat through the active trusted user channel; never send access tokens or credential files.
3. Optional: set `FULCRA_CONTEXT_SCRIPTS=/path/to/local/service/scripts` only if your host provides a local `fulcra_data_service.py`; the published `fulcra-context` skill is docs-first and does not ship helper scripts.
4. Collect data: `python3 collect_briefing_data.py --location "Your+City"`
5. Agent reads the JSON and composes a briefing using the tone rules in SKILL.md
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
## Quick Start

1. Install prerequisites: `uv` and `jq`
2. Authorize: `uv tool run fulcra-api auth login` (one-time, the user approves; the CLI can create the account if needed). Fulcra accounts include 5 GB of storage free forever and do not require an API key. For remote agents, surface only the printed device URL and code to the intended user in chat through the active trusted user channel; never send access tokens or credential files.
3. Optional: set `FULCRA_CONTEXT_SCRIPTS=/path/to/local/service/scripts` only if your host provides a local `fulcra_data_service.py`; the published `fulcra-context` skill is docs-first and does not ship helper scripts.
4. Collect data: `python3 collect_briefing_data.py --location "Your+City"`
5. Agent reads the JSON and composes a briefing using the tone rules in SKILL.md
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
For remote agents, do not rely on the agent host's local browser. Keep the CLI running, surface the printed device authorization URL and code to the intended user in chat through the active trusted user channel, and wait for approval. The user can approve from any browser on any device. Never send access tokens or credential files.

Credentials persist to `~/.config/fulcra/credentials.json`; the CLI refreshes access tokens as needed.

The Fulcra CLI changes quickly. Before relying on new auth options, inspect live help:
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Rp1

Medium
Category
MCP Rug Pull
Confidence
92% confidence
Finding
The README instructs users to run `uv tool run fulcra-api` without pinning a specific package version. That creates a supply-chain risk because future or compromised releases of the tool could change behavior and be executed during authentication, especially in an agent-oriented workflow where users may follow instructions verbatim.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill clearly expects shell execution and environment-dependent behavior, but it declares no explicit tool scope or permissions boundary. That mismatch can cause an agent platform to overgrant or ambiguously grant capabilities, increasing the chance of unintended command execution or data access when handling sensitive biometric and calendar information.

Session Persistence

Medium
Category
Rogue Agent
Content
Deliver a personalized morning briefing calibrated to how the human actually slept. Bad night? Keep it short and gentle. Great sleep? Go deep on the day ahead.

This is the lightweight morning workflow on top of **[fulcra-context](../fulcra-context/SKILL.md)**. Fulcra gives agents and their humans scoped, secure access to read and write real-world context and shared human/agent memory: attention, events, location, calendar, health, wearables, and other streams.

## What You'll Compose
Confidence
80% confidence
Finding
The skill is framed as a read-oriented morning briefing, yet it references a broader platform that provides read and write access to highly sensitive human context and shared memory. Without explicit scoping in this skill, that creates a risk that agents inherit broader persistent access than necessary, enabling overcollection, unintended writes, or long-lived storage of intimate data.

Rp1

Medium
Category
MCP Rug Pull
Confidence
89% confidence
Finding
Using `uv tool run fulcra-api` without a pinned version means the skill may execute whatever package version is current at runtime. That creates supply-chain and behavior-drift risk: a later release could change auth flow, expand capabilities, or introduce malicious or vulnerable code while the skill continues to trust it implicitly.

Rp1

Medium
Category
MCP Rug Pull
Confidence
89% confidence
Finding
This invocation relies on an unpinned external CLI version during security-sensitive authentication operations. If the upstream package changes unexpectedly, the auth UX, scopes, or token handling behavior may change in ways the skill does not anticipate, creating supply-chain and credential-exposure risk.

Rp1

Medium
Category
MCP Rug Pull
Confidence
89% confidence
Finding
Telling agents to inspect live help from an unpinned CLI still trusts the latest installed package and normalizes dynamic behavior from an uncontrolled dependency. In a sensitive workflow involving biometrics and calendar data, that increases the blast radius of any compromised or materially changed release.

Rp1

Medium
Category
MCP Rug Pull
Confidence
89% confidence
Finding
The fallback path explicitly uses the same unpinned CLI for direct JSON access to sensitive personal data. Because it may be run unattended by agents, any compromised or unexpected upstream release could alter outputs or execute harmful behavior with access to authenticated context.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill instructs sending the user's city or location to `wttr.in`, a third-party service, but the privacy implications are not clearly disclosed at the point of use. In this context, location is sensitive and is combined with sleep, biometrics, and calendar data, so even coarse location sharing can meaningfully increase profiling risk.

Rp1

Medium
Category
MCP Rug Pull
Confidence
88% confidence
Finding
The fallback troubleshooting workflow instructs use of an unpinned CLI command in a production-like agent context. This preserves a supply-chain exposure path even when the main collector cannot run, which is especially risky because operators may use it under time pressure and with elevated trust.

Rp1

Medium
Category
MCP Rug Pull
Confidence
88% confidence
Finding
An unpinned auth-help command still depends on a mutable external package and can surface changed or malicious behavior. In security-sensitive authentication flows, even help and usage guidance should come from a trusted, version-controlled source.

Rp1

Medium
Category
MCP Rug Pull
Confidence
88% confidence
Finding
The `data-updates` command is invoked through an unpinned external dependency, so both code execution and output semantics may drift over time. Because this command touches personal-context freshness data, a compromised update could leak or mishandle sensitive metadata.

Rp1

Medium
Category
MCP Rug Pull
Confidence
88% confidence
Finding
Using an unpinned `calendar-events` CLI in a workflow that reads sensitive schedules increases supply-chain risk and output unpredictability. Since calendar data can reveal meetings, locations, and relationships, any unexpected change in the tool can have outsized privacy impact.

Rp1

Medium
Category
MCP Rug Pull
Confidence
88% confidence
Finding
The auth-verification step again relies on an unpinned external CLI with access to account context. Repeatedly embedding mutable dependency execution throughout the skill increases overall attack surface and makes the workflow hard to audit or reproduce safely.

Rp1

Medium
Category
MCP Rug Pull
Confidence
84% confidence
Finding
Using 'uv tool run fulcra-api' without a pinned version introduces supply-chain risk because the resolved tool can change over time or be influenced by package publication state. In a skill that accesses sleep, biometrics, calendar, and other sensitive context, a compromised or incompatible upstream tool could exfiltrate data or alter behavior silently.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run_fulcra_json(*args: str) -> Any:
    command = os.environ.get("FULCRA_CLI_COMMAND", "uv tool run fulcra-api").split()
    result = subprocess.run(
        [*command, *args],
        capture_output=True,
        text=True,
Confidence
95% confidence
Finding
This subprocess execution is dangerous because the executable and its arguments are derived from the FULCRA_CLI_COMMAND environment variable, allowing a caller who controls the runtime environment to replace the intended Fulcra CLI with an arbitrary program. Although shell injection is avoided by using a list, this still permits arbitrary code execution through environment-controlled command selection in a skill that handles sensitive personal context.

Tainted flow: 'command' from os.environ.get (line 48, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Content
def run_fulcra_json(*args: str) -> Any:
    command = os.environ.get("FULCRA_CLI_COMMAND", "uv tool run fulcra-api").split()
    result = subprocess.run(
        [*command, *args],
        capture_output=True,
        text=True,
Confidence
98% confidence
Finding
There is a true tainted flow from the FULCRA_CLI_COMMAND environment variable into subprocess.run, enabling arbitrary executable selection. In an agent/skill environment where environment variables may be influenced by deployment, wrappers, or other tooling, this can turn a data-collection script into an arbitrary command runner with access to sensitive briefing inputs and outputs.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The skill performs an external internet fetch for weather despite its description focusing on Fulcra-context collection, which creates undisclosed data egress and violates least surprise. Because the skill processes highly personal morning-briefing context, any undeclared outbound network access is more concerning: users may reasonably expect local/private aggregation, not third-party transmission.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The weather lookup sends user-provided location information to wttr.in without any visible warning, consent flow, or indication that third-party sharing will occur. Even if the location is only a city, this is still personal context, and in combination with the morning-briefing use case it creates avoidable privacy exposure.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def get_weather(location: str) -> dict[str, Any]:
    try:
        result = subprocess.run(
            ["curl", "-s", f"wttr.in/{location}?format=%l:+%c+%t+%h+%w"],
            capture_output=True,
            text=True,
Confidence
88% confidence
Finding
This subprocess makes an outbound network request to wttr.in using user-supplied location data, creating a privacy leak and expanding the skill's capabilities beyond local Fulcra-context collection. While the invocation is not shell-based, it still transmits potentially sensitive location information to an external third party without explicit disclosure or consent handling.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
Executing curl introduces unnecessary external command and network capability for a skill whose core purpose is collecting Fulcra context. This broadens the attack surface, complicates auditing, and enables data egress to a third party in a context involving sensitive behavioral and biometric data.

Static analysis

No suspicious patterns detected.