Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .deepsec/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
node_modules/
.env*.local

# Scan output — regenerated by `deepsec scan` / `process`. INFO.md
# and SETUP.md (manually edited) stay tracked.
data/*/files/
data/*/runs/
data/*/reports/
data/*/project.json
23 changes: 23 additions & 0 deletions .deepsec/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Agent setup

This is a deepsec scanning workspace. Each registered project has its
own setup prompt at `data/<id>/SETUP.md` — open the relevant one when
asked to set a project up.

## Common tasks

- **Set up a project for scanning**: read `data/<id>/SETUP.md` and
follow it (read `node_modules/deepsec/SKILL.md`, then fill
`data/<id>/INFO.md` from the target codebase).
- **Add a new project**: run `deepsec init-project <root>` — it
scaffolds `data/<id>/` and prints/writes the setup prompt for the
new project.
- **Write a custom matcher** (only after a real true-positive shows you
a pattern worth keeping): read
`node_modules/deepsec/dist/docs/writing-matchers.md`.

## Reference

The deepsec skill is at `node_modules/deepsec/SKILL.md` (after
`pnpm install`). The full docs ship at
`node_modules/deepsec/dist/docs/`.
74 changes: 74 additions & 0 deletions .deepsec/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# deepsec

This directory holds the [deepsec](https://www.npmjs.com/package/deepsec)
config for the parent repo. Checked into git so teammates inherit
project context (auth shape, threat model, custom matchers); generated
scan output is gitignored.

Currently configured project: `sdk-react-native` (target: `..`).

## Setup

1. `pnpm install` — installs deepsec.
2. Add an AI Gateway / Anthropic / OpenAI token to `.env.local`. If
you already have `claude` or `codex` CLI logged in on this
machine, you can skip the token for non-sandbox runs (`process` /
`revalidate` / `triage`); deepsec auto-detects and reuses the
subscription. See
`node_modules/deepsec/dist/docs/vercel-setup.md` after install.
3. Open the parent repo in your coding agent (Claude Code, Cursor, …)
and have it follow `data/sdk-react-native/SETUP.md` to fill in
`data/sdk-react-native/INFO.md`.

## Daily commands

```bash
pnpm deepsec scan
pnpm deepsec process --concurrency 5
pnpm deepsec revalidate --concurrency 5 # cuts FP rate
pnpm deepsec export --format md-dir --out ./findings
```

`--project-id` is auto-resolved while there's only one project in
`deepsec.config.ts`. Once you've added a second project, pass
`--project-id sdk-react-native` (or whichever id you want) explicitly.

`scan` is free (regex only). `process` is the AI stage (≈$0.30/file
on Opus by default). Run state goes to `data/sdk-react-native/`.

## Adding another project

To scan another codebase from this same `.deepsec/`:

```bash
pnpm deepsec init-project ../some-other-package # path relative to .deepsec/
```

Appends an entry to `deepsec.config.ts` and writes
`data/<id>/{INFO.md,SETUP.md,project.json}`. Open the new SETUP.md
in your agent to fill in INFO.md.

## Layout

```
deepsec.config.ts Project list (one entry per scanned repo)
data/sdk-react-native/
INFO.md Repo context — checked into git, hand-curated
SETUP.md Agent setup prompt — checked in, deletable
project.json Generated (gitignored)
files/ One JSON per scanned source file (gitignored)
runs/ Run metadata (gitignored)
reports/ Generated markdown reports (gitignored)
AGENTS.md Pointer for coding agents
.env.local Tokens (gitignored)
```

## Docs

After `pnpm install`:

- Skill: `node_modules/deepsec/SKILL.md`
- Full docs: `node_modules/deepsec/dist/docs/{getting-started,configuration,models,writing-matchers,plugins,architecture,data-layout,vercel-setup,faq}.md`

Or browse on
[GitHub](https://github.com/vercel/deepsec/tree/main/docs).
81 changes: 81 additions & 0 deletions .deepsec/data/sdk-react-native/INFO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# sdk-react-native

## What this codebase does

`@formo/analytics-react-native` — a client-side analytics SDK (npm
library) embedded into third-party React Native dApps. It tracks wallet
events (connect / disconnect / signature / transaction / chain), screen
views, and custom events, batches them in `EventQueue`, and POSTs them
to `https://events.formo.so/v0/raw_events`. Optional Wagmi integration
(`WagmiEventHandler`) auto-captures wallet activity. There is **no
server component** in this repo — it is shipped code that runs inside
other people's apps. Classic web vulns (SQLi, SSRF, server authz) mostly
do not apply; data-handling and supply-chain concerns dominate.

## Auth shape

There is no user/session auth. The only credential is the **`writeKey`**
— a *public, write-only* ingest key intentionally bundled into client
apps and sent as `Authorization: Bearer ${writeKey}` via
`EVENTS_API_REQUEST_HEADER` (`constants/config.ts`). Treat it as
non-secret. The relevant gates instead are:

- `hasOptedOutTracking()` / `CONSENT_OPT_OUT_KEY` + `setConsentFlag` /
`getConsentFlag` / `removeConsentFlag` (`lib/consent`).
- `isBlockedAddress` / `BLOCKED_ADDRESSES` (`utils/address.ts`).
- `validateAddress` (EVM checksum + Solana) before an address is
attached to any event.

## Threat model

Highest impact: (1) PII / sensitive-data exfiltration — the SDK collects
wallet addresses, the **raw message text being signed**, device info,
deep-link URLs, and UTM/referrer attribution; anything that logs,
persists, or ships a private key or full signature secret is critical.
(2) Consent bypass — events generated or flushed after the user opted
out. (3) Supply-chain / untrusted input — host-app-supplied event
`properties` and deep-link URLs flow into the outbound payload.

## Project-specific patterns to flag

- **Signature capture leaking secrets.** `signature()` /
`createSignatureEvent` (`EventFactory`) and `WagmiEventHandler`
mutation tracking store `message` + optional `signatureHash` only.
Flag any path that captures a private key, mnemonic, or the produced
signature itself beyond `signatureHash`.
- **Consent-gate bypass.** Every new event entry point must check
opt-out before `eventQueue.enqueue`, and opt-out must call
`eventQueue.clear()`. Flag new track paths that skip the consent
check.
- **Unvalidated address pass-through.** Addresses attached to events
must go through `validateAddress` / `isBlockedAddress`; flag raw
user/wallet address used directly in a payload.
- **Untrusted properties / deep-link URLs** merged into event payloads
(`parseTrafficSource`, `startDeepLinkCapture`, custom `track`
properties) without sanitization — prototype-pollution or oversized
payload risk.

## Known false-positives

- `writeKey` in the `Bearer` header / bundled in client config — public
write-only key by design, **not** a leaked secret.
- `options.apiHost` overriding the ingest endpoint — intended
self-host/proxy support; not SSRF (runs in the host app's own
process, configured by that app's developer).
- `generateUUID()` using `Math.random()` (`utils/hash.ts`) — analytics
dedup/anon IDs, not security tokens. Acceptable.
- **Minute-rounded `message_id` deduplication** (`generateMessageId` →
`toDateHourMinute`, `lib/event/EventQueue.ts`) — intentional and
**by design**. This is the *canonical cross-SDK + backend dedup
contract* shared with `@formo/analytics` (web) and the
`events.formo.so` ingest pipeline; content-identical events colliding
within the same wall-clock minute is expected behavior, not a bug. Do
**not** flag or "fix" this — including the BUG finding
`other-deduplication-data-loss`. The `message_id` contract may only
change via coordinated web-SDK + backend + RN sign-off, never as an
SDK-local patch.
- Unencrypted `AsyncStorage` / `MemoryStorage` fallback — only stores
anon id + consent flag, non-sensitive by design.
- Hardcoded `SOLANA_SYSTEM_ADDRESSES` / `BLOCKED_ADDRESSES` — public
constants, not secrets.
- Anything under `src/__tests__/` — fixtures and mocks.
55 changes: 55 additions & 0 deletions .deepsec/data/sdk-react-native/SETUP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Agent setup for `sdk-react-native`

This is a deepsec scanning workspace. Project `sdk-react-native` was just registered
(target: `..`). Setup is incomplete — `data/sdk-react-native/INFO.md`
still has placeholder sections.

## What to do

1. **Read the deepsec skill.** After `pnpm install`, the file is at
`node_modules/deepsec/SKILL.md`. It maps every doc topic to a file
under `node_modules/deepsec/dist/docs/`. Read `getting-started.md`,
`configuration.md`, and `writing-matchers.md` (skim the rest).

2. **Fill in `data/sdk-react-native/INFO.md`.** It's auto-injected into the AI
prompt for every batch — keep it short and selective.

**Length budget: 50–100 lines total.** Verbose context dilutes
signal in the scanner's prompt window. The goal is "what would a
reviewer miss if they didn't read this?", not exhaustive enumeration.

**Per-section rubric**:
- Pick 3–5 representative items per section. **Don't list every
file, helper, or callsite** — pick the patterns.
- Name primitives by their public name (e.g. `withAuthentication`,
`auth.can()`, `isTeamAdmin`). **No line numbers.** Don't enumerate
more than 5 paths in any list.
- Skip generic CWE categories — built-in matchers already cover
"SSRF", "SQL injection", "XSS". Cover what's *project-specific*:
internal auth helpers, custom middleware names, fork-specific
stubs, intended-public endpoints.
- One short paragraph or 3–5 short bullets per section. Not both.

Source material (read in this order, stop when you have enough):
- `../README.md`
- any `AGENTS.md` / `CLAUDE.md` in `..`
- `../package.json` (or `go.mod`, `pyproject.toml`, etc.)
- 5–10 representative code files (entry points, auth helpers) — not
a full code tour.

3. **(Optional) Add custom matchers** for repo-specific patterns the
built-in matchers won't catch. Read
`node_modules/deepsec/dist/docs/writing-matchers.md` first; the
workflow there starts from a confirmed finding and grows the matcher
from it. Don't add matchers speculatively — wait for a real TP.

## When you're done

The user will run:

```bash
pnpm deepsec scan --project-id sdk-react-native
pnpm deepsec process --project-id sdk-react-native
```

You can delete this file once setup is complete.
12 changes: 12 additions & 0 deletions .deepsec/data/sdk-react-native/tech.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"tags": [
"github-actions",
"node",
"react"
],
"sentinels": [
"package.json"
],
"detectedAt": "2026-05-16T23:06:59.117Z",
"rootPath": "/Users/yos/sdk-react-native"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The rootPath property contains an absolute path specific to a local environment (/Users/yos/...). This makes the configuration non-portable and leaks local system information. If this file is intended to be tracked in git, this path should be made relative (e.g., ".."). However, given that it also contains a detectedAt timestamp, this file appears to be a generated cache that should likely be added to .deepsec/.gitignore and removed from the repository.

}
8 changes: 8 additions & 0 deletions .deepsec/deepsec.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { defineConfig } from "deepsec/config";

export default defineConfig({
projects: [
{ id: "sdk-react-native", root: ".." },
// <deepsec:projects-insert-above>
],
});
12 changes: 12 additions & 0 deletions .deepsec/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "deepsec-workspace",
"version": "0.1.0",
"private": true,
"description": "deepsec scanning workspace",
"type": "module",
"workspaces": [],
"packageManager": "pnpm@9.15.4",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The packageManager version specified here (pnpm@9.15.4) is inconsistent with the version used in the root package.json (pnpm@10.27.0). It is recommended to keep these versions synchronized to ensure consistent dependency resolution and lockfile behavior across the entire repository. Before applying this change, verify that pnpm@10.27.0 is available on the official registry (e.g., npm view pnpm@10.27.0).

Suggested change
"packageManager": "pnpm@9.15.4",
"packageManager": "pnpm@10.27.0",
References
  1. Verify the existence of recent package versions on the official registry before accepting version changes.

"dependencies": {
"deepsec": "^2.0.8"
}
}
Loading