Back to skill

Security audit

Subjective Check-In

Security checks across malware telemetry and agentic risk

Overview

The skill does what it advertises, but it can silently read Fulcra sleep/calendar context and persist intimate wellness check-ins to Fulcra without an explicit save confirmation.

Install only if you are comfortable with an agent reading Fulcra sleep/calendar context and saving personal morning reflections to Fulcra. Prefer invoking it explicitly, review dry-run payloads first, and avoid setting FULCRA_API_BASE or FULCRA_CLI_COMMAND unless you fully trust the target.

SkillSpector

By NVIDIA
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • Rogue AgentSelf-Modification, Session Persistence
Findings (16)

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

Medium
Category
Data Flow
Content
env.setdefault("PYTHONUTF8", "1")
    cmd = [*shlex.split(CLI_COMMAND, posix=(os.name != "nt")), *args]
    try:
        proc = subprocess.run(cmd, env=env, text=True, capture_output=True, timeout=120)
    except (FileNotFoundError, subprocess.TimeoutExpired) as exc:
        return 1, f"CLI invocation failed: {exc}"
    if proc.returncode != 0:
Confidence
93% confidence
Finding
proc = subprocess.run(cmd, env=env, text=True, capture_output=True, timeout=120)

Tainted flow: 'req' from os.environ.get (line 133, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
headers["Content-Type"] = "application/json"
    req = urllib.request.Request(API_BASE + path, data=data, headers=headers, method=method)
    try:
        with urllib.request.urlopen(req, timeout=45) as resp:
            body = resp.read()
            return resp.status, body.decode() if body else ""
    except urllib.error.HTTPError as exc:
Confidence
92% confidence
Finding
with urllib.request.urlopen(req, timeout=45) as resp:

Tainted flow: 'cmd' from os.environ.get (line 330, credential/environment) → subprocess.check_output (code execution)

Medium
Category
Data Flow
Content
env.setdefault("PYTHONUTF8", "1")
    cmd = [*shlex.split(CLI_COMMAND, posix=(os.name != "nt")), "auth", "print-access-token"]
    try:
        token = subprocess.check_output(
            cmd, env=env, text=True, stderr=subprocess.DEVNULL, timeout=60
        ).strip()
    except (FileNotFoundError, subprocess.CalledProcessError, subprocess.TimeoutExpired) as exc:
Confidence
93% confidence
Finding
token = subprocess.check_output( cmd, env=env, text=True, stderr=subprocess.DEVNULL, timeout=60 ).strip()

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill instructs the agent to execute shell commands, access environment-based credentials, and make network-backed writes to Fulcra, but the skill metadata shown here declares no explicit permissions. That mismatch can bypass user/operator expectations and increases the risk of silent data access or exfiltration if the skill is invoked unexpectedly.

Description-Behavior Mismatch

Medium
Confidence
90% confidence
Finding
The skill reads and returns calendar event titles, even though the stated purpose only requires today's event count for morning context. This collects and exposes more personal data than necessary, increasing privacy risk if the output is surfaced to the model, logs, or downstream systems.

Vague Triggers

Medium
Confidence
84% confidence
Finding
The trigger phrases are broad enough that ordinary conversation about sleep, feelings, or starting the day could invoke the skill proactively without a clear request to store sensitive data. In this skill's context, unintended invocation is more dangerous because it reads sleep/calendar context and persists intimate subjective data to Fulcra.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The document explicitly describes sending user-authored check-in notes and structured annotations to Fulcra via direct REST and persisting them for later readback, but it does not mention user consent, retention, or any user-facing warning that sensitive mood, energy, and health-adjacent reflections leave the local session and are stored remotely. In the context of a subjective mental/physical check-in skill, that omission creates a real privacy risk because users may disclose intimate information they would not expect to be transmitted and retained in an external system.

Anti-Refusal Statement

High
Category
Anti-Refusal
Content
Tone rules that matter:
- Warm and concise beats thorough. One question at a time.
- Mirror their language. If they say "wiped," reflect "wiped."
- Don't moralize about sleep or screen time. You're capturing, not correcting.
- If they give a one-word answer, that's fine -- don't pry. Move on.

## Step 3 -- Save to Fulcra
Confidence
85% confidence
Finding
Don't moralize

Env Variable Harvesting

High
Category
Data Exfiltration
Content
global _token_cache
    if _token_cache:
        return _token_cache
    env_token = os.environ.get("FULCRA_ACCESS_TOKEN")
    if env_token:
        _token_cache = env_token.strip()
        return _token_cache
Confidence
70% confidence
Finding
os.environ.get("FULCRA_ACCESS_TOKEN

Env Variable Harvesting

High
Category
Data Exfiltration
Content
if env_token:
        _token_cache = env_token.strip()
        return _token_cache
    env = os.environ.copy()
    env["HOME"] = DEFAULT_HOME
    env.setdefault("PYTHONUTF8", "1")
    cmd = [*shlex.split(CLI_COMMAND, posix=(os.name != "nt")), "auth", "print-access-token"]
Confidence
60% confidence
Finding
os.environ.copy()

Env Variable Harvesting

High
Category
Data Exfiltration
Content
# --------------------------------------------------------------------------- read context

def run_cli(args: list[str]) -> tuple[int, str]:
    env = os.environ.copy()
    env["HOME"] = DEFAULT_HOME
    env.setdefault("PYTHONUTF8", "1")
    cmd = [*shlex.split(CLI_COMMAND, posix=(os.name != "nt")), *args]
Confidence
60% confidence
Finding
os.environ.copy()

Unvalidated Output Injection

High
Category
Output Handling
Content
env.setdefault("PYTHONUTF8", "1")
    cmd = [*shlex.split(CLI_COMMAND, posix=(os.name != "nt")), *args]
    try:
        proc = subprocess.run(cmd, env=env, text=True, capture_output=True, timeout=120)
    except (FileNotFoundError, subprocess.TimeoutExpired) as exc:
        return 1, f"CLI invocation failed: {exc}"
    if proc.returncode != 0:
Confidence
95% confidence
Finding
subprocess.run(cmd, env=env, text=True, capture_output

Credential Access

High
Category
Privilege Escalation
Content
context. "They're having a low-energy morning" is fine; reciting their physical
  symptoms, intentions, or exact sleep stages is not.
- Calendar titles can contain sensitive info -- summarize counts, don't broadcast titles.
- Never print access tokens, refresh tokens, or the credentials file.

## Where this fits (the Fulcra skill family)
Confidence
70% confidence
Finding
access tokens

Credential Access

High
Category
Privilege Escalation
Content
).strip()
    except (FileNotFoundError, subprocess.CalledProcessError, subprocess.TimeoutExpired) as exc:
        fail(
            "Could not get a Fulcra access token. Set FULCRA_ACCESS_TOKEN, or make the "
            f"Fulcra CLI runnable (`{CLI_COMMAND} auth login`). Underlying error: {exc}"
        )
    if not token:
Confidence
70% confidence
Finding
access token

Credential Access

High
Category
Privilege Escalation
Content
f"Fulcra CLI runnable (`{CLI_COMMAND} auth login`). Underlying error: {exc}"
        )
    if not token:
        fail("Fulcra CLI returned an empty access token. Run `auth login` again.")
    _token_cache = token
    return token
Confidence
70% confidence
Finding
access token

Session Persistence

Medium
Category
Rogue Agent
Content
2. **Have the conversation.** Ask the questions below in a natural back-and-forth,
   weaving in the context. Adapt to what they say -- if they volunteer their energy
   while answering the mood question, don't re-ask it.
3. **Save the check-in to Fulcra.** Once you've covered the ground, write it.
4. **Close warmly.** One or two sentences reflecting what you heard, plus their
   intention for the day. Don't recite the saved fields back like a receipt.
Confidence
87% confidence
Finding
write it. 4. **Close warmly.** One or two sentences reflecting what you heard, plus their intention for the day. Don't recite the saved fields back like a receipt. ## Step 1 -- Read context Run t

VirusTotal

63/63 vendors flagged this skill as clean.

View on VirusTotal

Static analysis

No suspicious patterns detected.