Back to skill

Security audit

Oura Ring

Security checks for vulnerabilities and agentic risk

Overview

This Oura health-data skill has a coherent purpose, but unsafe configuration and parsing could expose your token or run unwanted code, so it needs review before installation.

Install only after review or fixes. The main issues to resolve are restricting API calls to the official HTTPS Oura host, removing or strongly gating base-url overrides, rewriting morning_brief.sh so API JSON is passed as data rather than embedded into Python source, removing the hard-coded probe scripts, and storing the Oura token through a safer secret mechanism or with strict local file protections.

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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
cli.py:61
Finding

Oura bearer token can be transmitted to an arbitrary network host

Content
View full analysis
Dict[str, Any]: url = self.base_url.rstrip("/") + "/" + path.lstrip("/") # Oura V2 sometimes uses different base paths for detailed data # If the path is 'sleep' or 'readiness' or 'heartrate', it might be at /v2/usercollection/ # but let's check if we need to adjust based on the endpoint. headers = {"Authorization": f"Bearer {self.token}", "Accept": "application/json"} for attempt in range(self.max_retries + 1): try: resp = self._session.get(url, headers=headers, params=params, timeout=self.timeout_s) ``` The destination is selected without validation in each command, for example: ```python token, source = _load_token(args.env_file) base_url = args.base_url or os.getenv("OURA_BASE_URL") or DEFAULT_BASE_URL client = OuraClient(token=token, base_url=base_url, timeout_s=args.timeout) ``` The command-line option enabling this behavior is: ```python p.add_argument( "--base-url", help=f"Override API base URL (default: {DEFAULT_BASE_URL})", default=None, ) ``` ### Technical Analysis The CLI loads a sensitive OAuth bearer token and attaches it to every request through the `Authorization` header. However, the request destination can be replaced with an arbitrary value through either `--base-url` or the `OURA_BASE_URL` environment variable. There is no validation of: - The URL scheme. - Whether TLS is required. - The destination hostname. - Whether the hostname belongs to Oura. - URL user-information or unusual URL components. - Whether production credentials should be sent to a custom test server. Consequently, a URL ...[truncated 1863 chars]
Remediation
View remediation
str: parsed = urlparse(value) if parsed.scheme != "https": raise OuraError("The API base URL must use HTTPS.") if parsed.hostname not in ALLOWED_API_HOSTS: raise OuraError("The API host is not permitted.") if parsed.username or parsed.password: raise OuraError("URL user information is not permitted.") return value ``` 2. Apply validation after resolving the command-line argument and environment variable, before constructing `OuraClient`. 3. Prefer removing `--base-url` and `OURA_BASE_URL` from production usage if custom endpoints are not essential to the Skill's declared functionality. 4. If custom endpoints are required for testing: - Require a conspicuous development-only flag. - Do not use a production Oura token. - Require a separately named test credential. - Display the destination and request explicit confirmation when interactive. - Reject plaintext HTTP except for tightly controlled loopback-only testing. 5. Document the exact hosts that receive credentials and the OAuth scopes required by each command. 6. Recommend token revocation and replacement if an untrusted base URL may already have been used. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/morning_brief.sh:19
Finding

Arbitrary Python code execution through API JSON interpolation in the morning brief

Content
View full analysis
Remediation
View remediation
"$TMP_DIR/sleep.json" python3 "$PYTHON_CLI" --env-file "$ENV_FILE" --format json readiness \ > "$TMP_DIR/readiness.json" python3 "$PYTHON_CLI" --env-file "$ENV_FILE" --format json trends \ > "$TMP_DIR/trends.json" python3 - "$TMP_DIR" <<'PY' import json import pathlib import sys directory = pathlib.Path(sys.argv[1]) with (directory / "sleep.json").open(encoding="utf-8") as handle: sleep_data = json.load(handle) with (directory / "readiness.json").open(encoding="utf-8") as handle: readiness_data = json.load(handle) with (directory / "trends.json").open(encoding="utf-8") as handle: trends_data = json.load(handle) # Generate the brief using the parsed objects. PY ``` 3. Quote the heredoc delimiter as `<<'PY'` so the shell does not perform expansion inside the Python program. 4. Add `set -euo pipefail` and verify each CLI command succeeds before processing its output. 5. Validate response schemas and field types before using values. Treat every field received from the network as untrusted data. 6. Combine this fix with strict API host validation. Fixing only the wrapper injection would not prevent token disclosure, while fixing only the host validation would not safely handle a compromised or malformed upstream response. 7. Add regression tests containing triple-single-quote sequences and other metacharacters in API string fields to confirm they remain data and are never interpreted as Python code. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (41)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Claiming 7-day trend analysis while apparently only comparing a small recent window is misleading, and omitting required permissions for external data access further obscures runtime behavior. Misrepresentation of data processing and dependencies can lead to overbroad trust and inadequate review of privacy-sensitive health data handling.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding

Claiming 7-day trend analysis while apparently only comparing a small recent window is misleading, and omitting required permissions for external data access further obscures runtime behavior. Misrepresentation of data processing and dependencies can lead to overbroad trust and inadequate review of privacy-sensitive health data handling.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Claiming 7-day trend analysis while apparently only comparing a small recent window is misleading, and omitting required permissions for external data access further obscures runtime behavior. Misrepresentation of data processing and dependencies can lead to overbroad trust and inadequate review of privacy-sensitive health data handling.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

Claiming 7-day trend analysis while apparently only comparing a small recent window is misleading, and omitting required permissions for external data access further obscures runtime behavior. Misrepresentation of data processing and dependencies can lead to overbroad trust and inadequate review of privacy-sensitive health data handling.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

The skill instructs users to store an access token in a local .env file, which is a real credential-handling pattern. While common in development, this increases risk of accidental disclosure through filesystem access, backups, shell history, or misconfiguration, especially for sensitive health-data access tokens.

Content

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

Create skills/oura-ring/.env:

bash
cp skills/oura-ring/.env.example skills/oura-ring/.env
# then edit skills/oura-ring/.env

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Editing a local .env file to place OAuth credentials exposes token material outside a managed secret boundary. In a skill that accesses personal health data, even benign local-secret workflows deserve caution because compromise of the token can expose private data from the user's account.

Content

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

bash
cp skills/oura-ring/.env.example skills/oura-ring/.env
# then edit skills/oura-ring/.env

The CLI reads:

Self-Modification

High
Category
Rogue Agent
Confidence
85% confidence
Finding

Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Content

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

bash
cp skills/oura-ring/.env.example skills/oura-ring/.env
# then edit skills/oura-ring/.env

The CLI reads:

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 67)May include surrounding context.

text

4. After approving, you’ll be redirected to your Redirect URI with a `code=...` query parameter.
5. Exchange the code for an access token:

```bash
curl -X POST https://api.ouraring.com/oauth/token \

Credential Access

High
Category
Privilege Escalation
Confidence
76% confidence
Finding

The instruction to place the returned access_token into a local .env file creates a plaintext credential storage practice for a token that unlocks sensitive Oura data. If the file is exposed, an attacker can query private readiness, sleep, and related health metrics.

Content

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

md
6. Put the returned `access_token` into `skills/oura-ring/.env` as `OURA_TOKEN=...`.

Notes:
- Access tokens can expire; you may need to refresh using the `refresh_token`.
- Do **not** commit your `.env` file.

## Usage

Credential Access

High
Category
Privilege Escalation
Confidence
74% confidence
Finding

The documented usage passes an explicit path to a local .env file containing credentials. This can normalize insecure secret distribution and may leak file locations or encourage scripts and logs to reference sensitive credential sources.

Content

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

Readiness

bash
python3 skills/oura-ring/cli.py --env-file skills/oura-ring/.env --format json --pretty readiness

Sleep

Credential Access

High
Category
Privilege Escalation
Confidence
74% confidence
Finding

Using a local .env file for sleep-data retrieval is the same credential-handling concern: the token is stored and referenced in plaintext on disk. Because the token grants access to health-related information, compromise can directly affect user privacy.

Content

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

Sleep

bash
python3 skills/oura-ring/cli.py --env-file skills/oura-ring/.env --format json --pretty sleep

Trends (last 7 days; paginated)

Credential Access

High
Category
Privilege Escalation
Confidence
74% confidence
Finding

The trends command also depends on a local .env file, repeating the same plaintext secret-storage pattern. Repeated documentation of this approach increases the chance users adopt it in production-like environments where credential exposure has broader consequences.

Content

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

Trends (last 7 days; paginated)

bash
python3 skills/oura-ring/cli.py --env-file skills/oura-ring/.env --format json --pretty trends

Wrapper: Morning Readiness Brief

Credential Access

High
Category
Privilege Escalation
Confidence
72% confidence
Finding

Allowing override of the env-file path is not malicious by itself, but it extends the secret-loading surface and can lead to accidental use of the wrong file or unsafe paths. In combination with undeclared secret access, this makes credential handling less predictable and harder to audit.

Content

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

Override the env file location:

bash
OURA_ENV_FILE=/path/to/.env ./skills/oura-ring/scripts/morning_brief.sh

Run in mock mode (no token):

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · cli.py (reported line 10)May include surrounding context.

python
- trends:    fetch last 7 days of readiness (handles pagination)

Auth:
  Loads OURA_TOKEN from a .env file (python-dotenv) or from environment.

This is intended to be a small, public-facing reference implementation.
"""

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · cli.py (reported line 134)May include surrounding context.

python
- trends:    fetch last 7 days of readiness (handles pagination)

Auth:
  Loads OURA_TOKEN from a .env file (python-dotenv) or from environment.

This is intended to be a small, public-facing reference implementation.
"""

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · cli.py (reported line 381)May include surrounding context.

python
- trends:    fetch last 7 days of readiness (handles pagination)

Auth:
  Loads OURA_TOKEN from a .env file (python-dotenv) or from environment.

This is intended to be a small, public-facing reference implementation.
"""

Credential Access

High
Category
Privilege Escalation
Confidence
96% confidence
Finding

This code explicitly loads a local .env file and reads a personal access token, which is direct credential access. In the context of a skill, especially one handling personal health-related data, silently pulling credentials from disk increases the chance of unauthorized account access and misuse if the script is run in a broader agent environment.

Content

Scanner excerpt · probe_v2.py (reported line 11)May include surrounding context.

python
import httpx
from dotenv import load_dotenv

load_dotenv("/Users/sameerbajaj/clawd/skills/oura-ring/.env")
token = os.getenv("OURA_PERSONAL_ACCESS_TOKEN")
base_url = "https://api.ouraring.com/v2/usercollection"
headers = {"Authorization": f"Bearer {token}"}

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

The code explicitly accesses a local .env file to obtain a personal access token, which is credential handling behavior that can expose or misuse secrets if the script is run in an unintended environment or shared as-is. Because the token grants access to personal Oura account data, compromise or accidental use could expose sensitive health and activity information.

Content

Scanner excerpt · probe_v2_sessions.py (reported line 11)May include surrounding context.

python
import httpx
from dotenv import load_dotenv

load_dotenv("/Users/sameerbajaj/clawd/skills/oura-ring/.env")
token = os.getenv("OURA_PERSONAL_ACCESS_TOKEN")
base_url = "https://api.ouraring.com/v2/usercollection"
headers = {"Authorization": f"Bearer {token}"}

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/morning_brief.sh (reported line 7)May include surrounding context.

sh
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SKILL_DIR="$(dirname "$DIR")"
VENV_PATH="$SKILL_DIR/.venv"
ENV_FILE="$SKILL_DIR/.env"

if [ -f "$VENV_PATH/bin/activate" ]; then
    source "$VENV_PATH/bin/activate"

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill documentation describes use of environment variables and outbound network access to the Oura API, but the skill declares no corresponding tool scope or permissions. Missing capability declarations reduce transparency and can cause users or an agent framework to authorize behavior they did not explicitly review.

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 · SKILL.md (reported line 70)May include surrounding context.

  1. Exchange the code for an access token:
bash
curl -X POST https://api.ouraring.com/oauth/token \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d grant_type=authorization_code \
  -d client_id=CLIENT_ID \

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This code loads an OURA access token and then sends authenticated requests to the Oura API to retrieve sleep, readiness, stress, and resilience data. Although the module docstring describes authentication and API usage, there is no explicit user-facing warning, confirmation, or disclosure that running these commands transmits sensitive personal health data to a remote service.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The trends command claims to return readiness trends but also fetches sleep session data, which broadens collection beyond the advertised behavior. This is risky because sleep sessions can include additional health details, creating unnecessary data exposure and violating data-minimization expectations.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The code exposes resilience and stress commands that go beyond the declared skill scope of readiness, sleep, and readiness trends. In a health-data skill, undocumented collection paths are dangerous because they expand access to additional sensitive biometric data without clear user expectation, review, or consent boundaries.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The code loads a personal access token from a hard-coded absolute .env path and immediately uses it for API access. This creates an unnecessary secret-access capability tied to a specific local environment and makes the skill depend on hidden credentials without any runtime consent or boundary checks.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.