Back to skill

Security audit

creditkarma-fpx

Security checks for vulnerabilities and agentic risk

Overview

This skill is transparent about its goal, but it asks users to extract and reuse Credit Karma session credentials for financial data access in ways that need careful review.

Review before installing. Only use this on a trusted machine, with a reviewed and pinned fetchproxy CLI version if possible, and treat CKAT, CKTRKID, ACCESS, and REFRESH exactly like account passwords. Avoid shared systems, shell tracing, CI logs, terminal recording, and predictable /tmp files; revoke the Credit Karma session if any token output may have been exposed.

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
SKILL.md:32
Finding
Unpinned Global Installation of a Security-Sensitive Third-Party Package<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:32` **Vulnerability Type**: Unpinned third-party dependency installed globally **Risk Level**: Medium ### Vulnerable Code ```sh npm install -g @fetchproxy/cli # provides `fpx` ``` ### Technical Analysis The setup instructions install the latest available release of `@fetchproxy/cli` globally without an exact version pin, lockfile, or integrity verification. The CLI is subsequently paired with a browser extension and used to obtain the authenticated `CKAT` and `CKTRKID` Credit Karma cookies. Because no reviewed version is fixed, the code executed by this command can change after the Skill has been audited. npm installation can also execute package lifecycle scripts. Installing globally increases the package's reach beyond an isolated project environment. This is particularly sensitive because the installed CLI is entrusted with browser-session material that can authorize access to private financial information. The audit did not establish that the named package is currently malicious; the vulnerability is the unsafe, mutable supply-chain trust model. ### Attack Path 1. An attacker compromises the package publisher, npm account, package distribution channel, or a future package release. 2. The attacker publishes a malicious version under the same package name. 3. A user follows the Skill instructions and runs the unpinned global installation command. 4. npm downloads the attacker-controlled version and may execute its lifecycle scripts with the user's privileges. 5. The malicious CLI can execute local commands immediately or wait until the user pairs it with the browser extension. 6. Once invoked and paired, it may attempt to capture Credit Karma session cookies or transmit data accessible to the process. ### Impact Assessment Successful exploitation can execute code with the privileges of the user running npm. Depending on local npm configuration and how t ...[truncated 546 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `@fetchproxy/cli` to an exact, reviewed version instead of installing the latest release: ```sh npm install --save-exact @fetchproxy/cli@<reviewed-version> ``` 2. Prefer a project-local installation and invoke it through a controlled local path rather than modifying the global npm environment. 3. Commit and enforce a lockfile with integrity hashes. 4. Verify package ownership, provenance, signatures, and published integrity before installation. 5. Review package lifecycle scripts and consider installing with scripts disabled if they are unnecessary: ```sh npm ci --ignore-scripts ``` 6. Run the CLI under a minimally privileged account and grant browser-cookie access only for the required Credit Karma domain and cookie names. 7. Document a reviewed version-upgrade process so dependency changes receive a new security assessment before deployment. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
references/requests.md:65
Finding
Financial Records and Session Tokens Written to Predictable Shared Temporary Files<![CDATA[ ## Vulnerability Details **File Location**: `references/requests.md:65-75, 103-125, 136-154` **Vulnerability Type**: Unsafe temporary-file handling and plaintext credential storage **Risk Level**: High ### Vulnerable Code The first transaction response is written to a fixed path: ```sh build_body null > /tmp/ck-body.json # ck-client-name MUST be exactly `prime_web` (`web` is rejected) and # ck-client-version must be non-empty; its value is not checked. Nothing else # is required — no cookies, no Origin/Referer/User-Agent. curl -s https://api.creditkarma.com/graphql -X POST \ -H "Authorization: Bearer $ACCESS" \ -H 'Content-Type: application/json' \ -H 'ck-client-name: prime_web' \ -H 'ck-client-version: 2.0.31' \ --data @/tmp/ck-body.json > /tmp/ck-resp.json ``` Pagination repeatedly overwrites the same predictable response file containing financial transaction data: ```sh after=null while :; do build_body "$after" > /tmp/ck-body.json curl -s https://api.creditkarma.com/graphql -X POST \ -H "Authorization: Bearer $ACCESS" \ -H 'Content-Type: application/json' \ -H 'Origin: https://www.creditkarma.com' \ -H 'Referer: https://www.creditkarma.com/' \ -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36' \ --data @/tmp/ck-body.json > /tmp/ck-resp.json jq -r '.data.prime.transactionsHub.transactionPage.transactions[] | [.date, .amount.asCurrencyString, .description] | @tsv' /tmp/ck-resp.json has_next=$(jq -r '.data.prime.transactionsHub.transactionPage.pageInfo.hasNextPage' /tmp/ck-resp.json) [ "$has_next" = "true" ] || break after=$(jq -c '.data.prime.transactionsHub.transactionPage.pageInfo.endCursor' /tmp/ck-resp.json) done ``` The refresh response, including reusable credentials, is also written to a fixed path: ```sh GLID=$(node -e "console.log(JSON.parse(Buffer.from(process.argv[1].split('.')[1],'base64url').to ...[truncated 4035 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Set a restrictive file-creation mask before handling credentials or financial records: ```sh umask 077 ``` 2. Create a unique private temporary directory atomically: ```sh tmpdir=$(mktemp -d) || exit 1 trap 'rm -rf -- "$tmpdir"' EXIT HUP INT TERM ``` 3. Replace all fixed `/tmp/ck-*` paths with quoted paths inside the private directory: ```sh body_file="$tmpdir/body.json" response_file="$tmpdir/response.json" refresh_file="$tmpdir/refresh.json" ``` 4. Keep refresh responses in memory where practical instead of persisting tokens: ```sh refresh_response=$(curl --fail-with-body --silent --show-error ...) ACCESS=$(jq -er '.accessToken' <<<"$refresh_response") || exit 1 ``` 5. If a file is unavoidable, create it atomically with permissions `0600`, verify that it is a regular file owned by the current user, and delete it immediately after parsing. 6. Avoid following attacker-controlled symbolic links. Do not use predictable names in a shared directory. 7. Add cleanup handling for normal completion, command failure, interruption, and authentication errors. 8. Redact access tokens, refresh tokens, cookies, and financial payloads from terminal logs, debugging output, shell tracing, and error reports. 9. Consider storing only the minimum projected transaction fields required for the task and obtain explicit user consent before persisting financial records. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (18)

YARA rule 'info_stealer': Information stealer patterns (credential harvesting, browser data theft) [malware]

High
Category
YARA Match
Content
KID   # widen scope to these cookies
fpx pair -p creditkarma                                          # prints a pair code → approve in Transporter
```

Requirements: the **Transporter** browser extension installed, with an open
`www.creditkarma.com` tab you're signed into, and its Chrome **Site access**
allowing `creditkarma.com`. `CKAT`/`CKTRKID` are `HttpOnly` (invisible to page
JS) but `fpx cookies` reads them via the extension's `chrome.cookies.get`,
same as `@fetchproxy/bootstrap` does inside the MCP. Pairing persists across
invocations.

## Capture the session (once per shell / once the token goes stale)

```sh
fpx cookies -p creditkarma
# {"CKAT":"<accessJWT>%3B<refreshJWT>","CKTRKID":"<value>"}
```

`CKAT` packs both JWTs joined by a literal `%3B` (URL-encoded `;`). Split it:

```sh
COOKIES=$(fpx cookies -p creditkarma)
CKAT=$(jq -r '.CKAT' <<<"$COOKIES" | sed 's/%3B/;/')
CKTRKID=$(jq -r '.CKTRKID' <<<"$COOKIES")
ACCESS=${CKAT%%;*}
REFRESH=${CKAT#*;}
```

## Core call: fetch
Confidence
99% confidence
Finding
This section instructs use of a browser extension capability to read HttpOnly cookies from a signed-in Credit Karma session and then extract access and refresh JWTs for reuse. That behavior closely matches credential-harvesting patterns because it bypasses normal application boundaries and converts browser session secrets into portable credentials that can be replayed to access private financial data.

Credential Access

High
Category
Privilege Escalation
Content
```

If that value matches `UNAUTHENTICATED|UNAUTHORIZED|TOKEN_EXPIRED|401`
(case-insensitive), the access token expired — refresh it (below) and retry.
Anything else (schema drift, validation) is a real error, not an auth
failure — don't refresh on it. A `FORBIDDEN`/403-shaped code means
authenticated-but-not-authorized; refreshing won't help.
Confidence
94% confidence
Finding
This section discusses detecting token expiry and proceeding to refresh and retry, reinforcing an operational workflow for maintaining stolen or extracted authentication material. In context, the skill is not just using a session cookie in-browser; it teaches portable reuse of bearer credentials outside the normal browser boundary, which increases session hijacking and account access risk.

Credential Access

High
Category
Privilege Escalation
Content
`pageInfo.endCursor`, and stop when `pageInfo.hasNextPage` is `false`. See
`references/requests.md` for the full loop.

## Refreshing the access token (no need to re-run `fpx` for this)

The access token is short-lived (~10 min). Refresh with the `refreshToken`
you already extracted — this is a plain `curl`, not another `fpx` capture:
Confidence
98% confidence
Finding
The skill explicitly instructs the user to refresh an access token using a previously extracted refresh token, enabling ongoing replay of authenticated session material. Refresh tokens are long-lived and especially sensitive; exposing them in shell variables and curl commands materially elevates the risk of persistent account compromise if copied, logged, or leaked.

Credential Access

High
Category
Privilege Escalation
Content
## Refreshing the access token (no need to re-run `fpx` for this)

The access token is short-lived (~10 min). Refresh with the `refreshToken`
you already extracted — this is a plain `curl`, not another `fpx` capture:

```sh
Confidence
98% confidence
Finding
By presenting a concrete curl-based refresh flow with Authorization and Cookie headers containing live session material, the skill operationalizes credential replay outside the browser. In the context of a consumer financial service, this significantly increases the blast radius of accidental disclosure and makes unauthorized reuse easier.

Credential Access

High
Category
Privilege Escalation
Content
value is a real GraphQL error (schema drift, validation) — surface it, don't
refresh.

## 2. Refresh the access token

```sh
GLID=$(node -e "console.log(JSON.parse(Buffer.from(process.argv[1].split('.')[1],'base64url').toString()).glid||'')" "$ACCESS")
Confidence
91% confidence
Finding
The skill explicitly documents how to refresh access using bearer and refresh tokens derived from captured session cookies, which materially enables credential reuse if those values are exposed. In the context of a financial service, this is particularly sensitive because stolen tokens can grant ongoing access to transaction data and potentially extend session lifetime.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The skill explicitly instructs the user to capture authenticated Credit Karma session cookies and split them into access and refresh tokens, but the warning about handling these secrets appears much later and is not prominent. Because these cookies/tokens grant access to highly sensitive financial transaction data and can be replayed, normalizing their extraction without front-loaded risk disclosure materially increases the chance of credential misuse or accidental exposure.

External Transmission

Medium
Category
Data Exfiltration
Content
```sh
GLID=$(node -e "console.log(JSON.parse(Buffer.from(process.argv[1].split('.')[1],'base64url').toString()).glid||'')" "$ACCESS")

curl -s https://www.creditkarma.com/member/oauth2/refresh -X POST \
  -H 'Content-Type: application/json' \
  -H 'Origin: https://www.creditkarma.com' \
  -H 'Referer: https://www.creditkarma.com/' \
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
```sh
GLID=$(node -e "console.log(JSON.parse(Buffer.from(process.argv[1].split('.')[1],'base64url').toString()).glid||'')" "$ACCESS")

curl -s https://www.creditkarma.com/member/oauth2/refresh -X POST \
  -H 'Content-Type: application/json' \
  -H 'Origin: https://www.creditkarma.com' \
  -H 'Referer: https://www.creditkarma.com/' \
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
actually calls (from `src/client.ts`). Both are unpublished, reverse-engineered
CK-internal endpoints — verified live by the MCP's own client, not guessed.

- `POST https://api.creditkarma.com/graphql` — the transactions query.
- `POST https://www.creditkarma.com/member/oauth2/refresh` — access-token refresh.

Everything else the MCP exposes (`ck_list_transactions`,
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
actually calls (from `src/client.ts`). Both are unpublished, reverse-engineered
CK-internal endpoints — verified live by the MCP's own client, not guessed.

- `POST https://api.creditkarma.com/graphql` — the transactions query.
- `POST https://www.creditkarma.com/member/oauth2/refresh` — access-token refresh.

Everything else the MCP exposes (`ck_list_transactions`,
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
actually calls (from `src/client.ts`). Both are unpublished, reverse-engineered
CK-internal endpoints — verified live by the MCP's own client, not guessed.

- `POST https://api.creditkarma.com/graphql` — the transactions query.
- `POST https://www.creditkarma.com/member/oauth2/refresh` — access-token refresh.

Everything else the MCP exposes (`ck_list_transactions`,
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
actually calls (from `src/client.ts`). Both are unpublished, reverse-engineered
CK-internal endpoints — verified live by the MCP's own client, not guessed.

- `POST https://api.creditkarma.com/graphql` — the transactions query.
- `POST https://www.creditkarma.com/member/oauth2/refresh` — access-token refresh.

Everything else the MCP exposes (`ck_list_transactions`,
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The documentation instructs users to extract live Credit Karma session cookies and split them into access and refresh JWTs, but provides no warning that these are highly sensitive credentials. Anyone with access to shell history, temp files, logs, or copied command output could reuse them to access the user's financial account data or maintain session access via refresh.

External Transmission

Medium
Category
Data Exfiltration
Content
# ck-client-name MUST be exactly `prime_web` (`web` is rejected) and
# ck-client-version must be non-empty; its value is not checked. Nothing else
# is required — no cookies, no Origin/Referer/User-Agent.
curl -s https://api.creditkarma.com/graphql -X POST \
  -H "Authorization: Bearer $ACCESS" \
  -H 'Content-Type: application/json' \
  -H 'ck-client-name: prime_web' \
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
# ck-client-name MUST be exactly `prime_web` (`web` is rejected) and
# ck-client-version must be non-empty; its value is not checked. Nothing else
# is required — no cookies, no Origin/Referer/User-Agent.
curl -s https://api.creditkarma.com/graphql -X POST \
  -H "Authorization: Bearer $ACCESS" \
  -H 'Content-Type: application/json' \
  -H 'ck-client-name: prime_web' \
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The skill sends authenticated requests to live Credit Karma endpoints to retrieve transaction data, but omits a clear user-facing warning that sensitive financial data is being transmitted and handled outside the normal product flow. This increases the chance users will run the commands in unsafe environments or automation without understanding the privacy implications.

External Transmission

Medium
Category
Data Exfiltration
Content
after=null
while :; do
  build_body "$after" > /tmp/ck-body.json
  curl -s https://api.creditkarma.com/graphql -X POST \
    -H "Authorization: Bearer $ACCESS" \
    -H 'Content-Type: application/json' \
    -H 'Origin: https://www.creditkarma.com' \
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The refresh flow places authentication material in Authorization headers, Cookie headers, shell variables, and JSON temp files without any secure-handling guidance. This creates multiple opportunities for token exposure through process listings, command history, filesystem artifacts, CI logs, or terminal capture, enabling session hijacking against a financial account.

Static analysis

No suspicious patterns detected.