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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 18)May include surrounding context.

md
## 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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
## 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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
## 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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
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:

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.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

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.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
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.

Content

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

md
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

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.

Content

No source excerpt is available for this finding.

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.

Content

No source excerpt is available for this finding.

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.

Content

No source excerpt is available for this finding.

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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

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.

Content

No source excerpt is available for this finding.

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.

Content

No source excerpt is available for this finding.

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.

Content

No source excerpt is available for this finding.

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.

Content

No source excerpt is available for this finding.

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.

Content

No source excerpt is available for this finding.

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.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
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.

Content

Scanner excerpt · collect_briefing_data.py (reported line 49)May include surrounding context.

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,

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

Medium
Category
Data Flow
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.

Content

Scanner excerpt · collect_briefing_data.py (reported line 49)May include surrounding context.

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,

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
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.

Content

Scanner excerpt · collect_briefing_data.py (reported line 247)May include surrounding context.

python
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,

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.