
Research
/Security News
77 Firefox Extensions Linked to Crypto Wallet and Credential Theft
Socket uncovered 77 linked Firefox extensions, including 40 that steal wallet secrets or credentials and 37 deceptive sports-score shells.
usrcp-github
Advanced tools
GitHub capture adapter for USRCP - polls the REST API for pull requests authored by the configured user and appends them to the local ledger
GitHub capture adapter for USRCP. Polls GitHub's REST search API for pull requests authored by the configured user, and appends them to the local USRCP ledger as encrypted timeline events. Capture-only in v1 - no reader/bot.
cd packages/usrcp-github
npm install
npm run build
node dist/index.js # capture loop
node dist/index.js --reset-config # re-prompt all config
First run is interactive. The wizard validates your personal access
token against /user before persisting, lists the orgs your token
can see, and lets you pick which to allowlist. A typo fails at the
wizard, not at first poll.
Either token type works:
ghp_*): needs repo (or public_repo if you
only care about public PRs) and read:org for the org listing
step in setup.github_pat_*): grant Pull requests: read
on every repo whose PRs you want captured.The token is encrypted at rest under the USRCP master key (same
envelope as private.pem), in addition to file mode 0600.
~/.usrcp/github-config.json at mode 0600:
{
"github_token": "enc:<base64-AES-GCM-envelope>",
"github_login": "chad",
"allowlisted_orgs": ["anthropics", "usrcp"],
"domain": "github",
"poll_interval_s": 600,
"last_synced_at": "2026-05-17T12:00:00.000Z",
"last_merged_at": "2026-05-17T14:00:00.000Z",
"last_closed_at": "2026-05-17T13:00:00.000Z",
"last_issue_opened_at": "2026-05-17T15:00:00.000Z",
"last_issue_commented_at": "2026-05-17T16:00:00.000Z",
"last_pr_reviewed_at": "2026-05-17T17:00:00.000Z"
}
Set allowlisted_orgs: [] to capture across every repo the token
can see (user-owned + public-collaborator). When the list is
non-empty, GitHub search filters server-side via org:<slug>
clauses so out-of-scope orgs' PRs are never fetched.
The adapter runs six independent queries per tick, each with its own cursor:
| Cursor field | Query qualifier | Event fired |
|---|---|---|
last_synced_at | author:X type:pr created:>{cursor} | pr_opened |
last_merged_at | author:X type:pr is:merged merged:>{cursor} | pr_merged |
last_closed_at | author:X type:pr is:closed is:unmerged closed:>{cursor} | pr_closed |
last_issue_opened_at | author:X type:issue created:>{cursor} | issue_opened |
last_issue_commented_at | commenter:X updated:>{cursor} + listComments | issue_commented |
last_pr_reviewed_at | reviewed-by:X type:pr updated:>{cursor} + listReviews | pr_reviewed |
Two-stage fetches (issue_commented and pr_reviewed) work the same way: search finds candidate issues/PRs the user has touched since the cursor, then a REST endpoint per candidate returns the underlying objects (comments or reviews) filtered to the user's authorship + strictly-greater-than-cursor timestamp. Idempotency keys ensure exactly-once even when the same candidate appears in multiple ticks.
Both two-stage flows handle partial failures the same way:
listComments / listReviews fails on any candidate this tick, the cursor pins at the input value so the next tick re-processes the entire window.candidate.updated_at so candidates the user historically touched don't get re-fetched indefinitely when only others have new activity.Each PR captures at most one terminal event because is:merged and is:closed is:unmerged are mutually exclusive in the search index. A merged PR can never un-merge, so pr_merged is genuinely terminal.
Each PR contributes up to two events (pr_opened + one terminal state event), plus a pr_reviewed event per review you submitted on someone else's PR. Each issue contributes one issue_opened. Comments add one issue_commented per author-matching comment. All events on the same issue/PR share channel_id = <owner>/<repo>#<number> (GitHub uses one numbering namespace per repo), so getRecentEventsByChannel returns the full lifecycle - PR open, comments, reviews, terminal state - in one shot.
Per-event detail:
pr_opened - tags ["github", "pull-request", "<owner>/<repo>"], idempotency github:pr:<owner>/<repo>#<number>. Detail includes title, body, url, state, merged, created_at, updated_at.pr_merged / pr_closed - tags [..., "merged"] or [..., "closed"], idempotency github:pr-{merged,closed}:<owner>/<repo>#<number>. Detail includes state_at (the merge/close timestamp).issue_opened - tags ["github", "issue", "<owner>/<repo>"], idempotency github:issue:<owner>/<repo>#<number>. Detail includes title, body, url, state, created_at, updated_at.issue_commented - tags ["github", "comment", "<pull-request|issue>", "<owner>/<repo>"], idempotency github:issue-comment:<comment_id>. thread_id = comment_id. Detail includes the full comment body, is_pr_parent flag, comment URL, parent issue URL, and timestamps.pr_reviewed - tags ["github", "review", "<approved|requested-changes|reviewed>", "<owner>/<repo>"], idempotency github:pr-review:<review_id>. thread_id = review_id. Detail includes review body (may be empty for plain Approves), state (APPROVED / CHANGES_REQUESTED / COMMENTED), submitted_at, pr_url, and the PR author's login. PENDING (draft) and DISMISSED reviews are skipped.external_user_id distinguishes who the "other party" was: the actor for pr_opened/issue_opened/issue_commented (always you), and the PR author for pr_reviewed (so agents can grep "reviews I did for Alice"). Title and body fields are encrypted under the domain key; everything else in detail goes through the global-key envelope.
GitHub Search API: 30 requests/minute for authenticated users.
Default poll interval is 600s with five paginated search queries
per tick (opened / merged / closed / issue_opened / commented-candidates
/ reviewed-candidates), so the rate-limit cost stays under
10/min. The two-stage flows then issue per-candidate REST calls
(listComments for issue_commented, listReviews for pr_reviewed);
those count against the much-higher 5000/hr core REST cap
(~80/min). For most users this hovers in the single digits per
tick.
Each search query caps at 1000 results - if you have more than 1000 events in the time window since a cursor, overflow is permanently dropped. In practice this only matters on first run; the daemon's first-run lookback is 5 minutes.
pulls.listReviews; the top-level review object
is captured, but per-line comments are deferred).pr_reopened events. The search index doesn't expose "was
closed, is now open" as a query, so reopens would require
state tracking that's deferred to a future PR.FAQs
GitHub capture adapter for USRCP - polls the REST API for pull requests authored by the configured user and appends them to the local ledger
The npm package usrcp-github receives a total of 514 weekly downloads. As such, usrcp-github popularity was classified as not popular.
We found that usrcp-github demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
/Security News
Socket uncovered 77 linked Firefox extensions, including 40 that steal wallet secrets or credentials and 37 deceptive sports-score shells.

Security News
NIST disclosed an unreleased AI tool called V-etalon and opened a broad inquiry into NVD modernization after years of automation plans produced no public enrichment system.

Security News
In his AI Council 2026 talk, Feross Aboukhadijeh covers recent package compromises, vulnerability discovery, and a more automated security model.