T09 · Insecure Skill Coding Practices
- Location
src/index.ts:108- Finding
Bearer API Key Is Written to Application Logs
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill has a coherent personal-data gateway purpose, but it automatically handles durable credentials and setup in ways users should review carefully before installing.
Review this before installing. It is meant to access personal data through PersonalDataHub, so some credential and network use is expected, but installation currently bootstraps services automatically, stores/reads a durable local API key, may log a full newly created key, and accepts hub URLs without clear trust boundaries. Prefer installing only in a controlled environment, with a trusted pinned PersonalDataHub CLI, validated localhost or HTTPS hub URL, and rotated keys if any logs may have captured credentials.
src/index.ts:108Bearer API Key Is Written to Application Logs
src/hub-client.ts:48Unvalidated Hub URL Can Receive Bearer Credentials and Sensitive Action Data
SKILL.md:9Install Hook Executes Unpinned Registry Tool and Broad Parent-Workspace Scripts
src/setup.test.ts:133Test Suite Reads the User's Real PersonalDataHub Credential File
This skill instructs reading a local credential file and performing local service checks/startup, while presenting itself primarily as a filtered gateway for personal data. In a personal-data context, undisclosed credential access and provisioning behavior materially increase risk because the agent may obtain reusable secrets and operational control over the hub.
This skill instructs reading a local credential file and performing local service checks/startup, while presenting itself primarily as a filtered gateway for personal data. In a personal-data context, undisclosed credential access and provisioning behavior materially increase risk because the agent may obtain reusable secrets and operational control over the hub.
This skill instructs reading a local credential file and performing local service checks/startup, while presenting itself primarily as a filtered gateway for personal data. In a personal-data context, undisclosed credential access and provisioning behavior materially increase risk because the agent may obtain reusable secrets and operational control over the hub.
This skill instructs reading a local credential file and performing local service checks/startup, while presenting itself primarily as a filtered gateway for personal data. In a personal-data context, undisclosed credential access and provisioning behavior materially increase risk because the agent may obtain reusable secrets and operational control over the hub.
This skill instructs reading a local credential file and performing local service checks/startup, while presenting itself primarily as a filtered gateway for personal data. In a personal-data context, undisclosed credential access and provisioning behavior materially increase risk because the agent may obtain reusable secrets and operational control over the hub.
Reading ~/.pdh/credentials.json exposes a reusable API key and service location to the agent. In a personal-data skill, that credential can enable broad access to email, GitHub-connected data, or staged outbound actions, making compromise or misuse particularly damaging.
If the tools above are not available, you can call the PersonalDataHub API directly via HTTP.
Credentials: Read ~/.pdh/credentials.json to get hubUrl and apiKey.
Pull data:
The troubleshooting flow instructs reading the credentials file to discover hubDir, exposing internal paths and potentially the same credential material during a support operation. This expands secret exposure into a path that users or agents may treat as low risk, increasing the chance of accidental leakage.
If the server is not running, find and start it:
# Check where PersonalDataHub is installed
cat ~/.pdh/credentials.json # look at hubDir
# Start the server
cd <hubDir> && node dist/index.js
The install flow creates an API key and saves it to a predictable plaintext location in the user's home directory. Predictable, file-based secret storage raises the risk of unintended access by other tools, agents, or local malware, especially when the key grants access to sensitive personal-data workflows.
The install hook bootstraps PersonalDataHub automatically:
1. Installs dependencies, builds the project, initializes the database
2. Creates an API key and saves it to `~/.pdh/credentials.json`
3. Starts the server in the background
After installation, open `http://localhost:3000` to connect Gmail/GitHub via OAuth.
The statement that agents read credentials automatically from ~/.pdh/credentials.json normalizes silent secret access by the skill. In context, this is more dangerous because the skill handles personal communications and outbound actions, so the credential can be used to access or stage highly sensitive operations without fresh user awareness.
After installation, open `http://localhost:3000` to connect Gmail/GitHub via OAuth.
Agents read credentials automatically from `~/.pdh/credentials.json` — no manual configuration needed.
## Query Syntax (Gmail)
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import { describe, it, expect, vi, afterEach } from 'vitest';
// Mock readCredentials so tests don't depend on real ~/.pdh/credentials.json
vi.mock('./setup.js', async (importOriginal) => {
const actual = await importOriginal() as Record<string, unknown>;
return {
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import { describe, it, expect, vi, afterEach } from 'vitest';
// Mock readCredentials so tests don't depend on real ~/.pdh/credentials.json
vi.mock('./setup.js', async (importOriginal) => {
const actual = await importOriginal() as Record<string, unknown>;
return {
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import { describe, it, expect, vi, afterEach } from 'vitest';
// Mock readCredentials so tests don't depend on real ~/.pdh/credentials.json
vi.mock('./setup.js', async (importOriginal) => {
const actual = await importOriginal() as Record<string, unknown>;
return {
The skill reads a local credentials file to obtain authentication material, which is a credential-access capability beyond simple data retrieval. In this skill's context, that is more dangerous because the plugin handles personal data and can silently bootstrap privileged access using local secrets the operator may not expect it to consume.
}
}
// Step 3: Check credentials file (~/.pdh/credentials.json)
if (!config?.hubUrl || !config?.apiKey) {
const creds = readCredentials();
if (creds) {
The code logs a newly created API key in plaintext, which can expose the credential to log files, consoles, telemetry pipelines, and other users on the host. Anyone who obtains those logs may be able to authenticate to the PersonalDataHub and access or manipulate personal data.
The skill looks for persistent credentials in the user's home directory and is documented to participate in self-enrollment, neither of which is justified by the stated role of proposing actions through a preexisting gateway. In skill contexts handling personal data, automatic credential discovery is especially risky because it enables silent access to sensitive systems without explicit user approval at runtime.
This code targets a known credential file location in the user's home directory, enabling the skill to obtain an API key for the PersonalDataHub without separate authorization in this flow. Because the hub governs personal emails and issues, access to this secret can expose sensitive data and enable downstream actions under the user's authority.
}
/** Path to the credentials file written by `npx pdh init`. */
export const CREDENTIALS_PATH = join(homedir(), '.pdh', 'credentials.json');
/**
* Read credentials from ~/.pdh/credentials.json.
The readCredentials function operationalizes credential access by loading and parsing the persistent credentials file, making the secret directly consumable by the skill. In this context, that materially increases the skill's ability to access personal-data infrastructure outside of a tightly controlled, user-mediated flow.
export const CREDENTIALS_PATH = join(homedir(), '.pdh', 'credentials.json');
/**
* Read credentials from ~/.pdh/credentials.json.
* Returns null if the file doesn't exist or is malformed.
*/
export function readCredentials(): Credentials | null {
The file implements autonomous discovery of a local PersonalDataHub and creates a fresh API key for the skill, which materially expands the skill's privileges beyond merely consuming gateway-filtered data. In the context of a skill whose stated purpose is data access through an existing access-control gateway, self-enrollment and credential minting are dangerous because they bypass expected provisioning controls and can silently grant the skill durable access.
The skill declares no explicit tool scope while its documented behavior includes network access and reading local files for credentials. That increases the chance an agent is granted broader capabilities than users expect, especially in a skill handling personal data and API keys.
Using npx pdh without pinning a version allows execution of whatever package version resolves at install time. This creates a supply-chain risk where a malicious or compromised package release could execute arbitrary code during installation or startup.
The direct HTTP fallback transmits authorization credentials and personal-data requests, but the documentation provides no explicit privacy or transport-security guidance. In a skill centered on sensitive personal data, omitting such warnings can lead to insecure deployment, accidental logging, or use of non-TLS endpoints.
The skill explicitly instructs agents to read ~/.pdh/credentials.json to obtain hubUrl and apiKey without a strong warning or consent gate. Access to local credential files gives the agent reusable secrets that could be abused for unauthorized data access or service actions beyond the immediate user request.
The skill is designed to send data over HTTP to a hub service, so external transmission is expected, but it still represents a real security concern because personal data and bearer tokens are being sent across a network boundary. The context makes this behavior necessary, not harmless; its safety depends on strict transport security and endpoint trust.
Pull data:
curl -X POST <hubUrl>/app/v1/pull \
-H "Authorization: Bearer <apiKey>" \
-H "Content-Type: application/json" \
-d '{"source": "gmail", "purpose": "reason for pulling data"}'
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.