Skip to content

Security: 16 low-severity findings in services, repositories and utils #1019

Open

Description

@chappie-daemon

CodeRabbit's historical security scan of this repository (scan e8c825ec-84c1-4a90-b646-61791714baf8, revision bc22677aba, generated 2026-11-01) reported this. It is an AI-generated finding, not a confirmed vulnerability: reachability is not established by the scan, and the report itself says so. Triage before treating it as exploitable.

ID Severity Category Location CWE
F-001 low ssrf src/utils/relay-probe/nip11-probe.ts:96-109 CWE-918
F-002 low denial of service src/services/wot-graph-service.ts:157-164 CWE-400
F-003 low denial of service src/utils/settings-config.ts:493-494 CWE-789
F-004 low ssrf src/utils/nip05.ts:156-171 CWE-918
F-005 low authorization bypass src/services/wot-graph-service.ts:158-164 CWE-863
F-007 low authorization bypass src/utils/settings.ts:119-122 CWE-863
F-008 low authorization bypass src/services/wot-graph-service.ts:93-96 CWE-863
F-009 low authorization bypass src/utils/admin-moderation.ts:272-272 -
F-010 low authorization bypass src/services/wot-graph-service.ts:93-97 CWE-863
F-012 low authorization bypass src/repositories/user-repository.ts:67-68 -
F-020 low denial of service src/services/event-import-service.ts:113-117 CWE-407
F-026 low denial of service src/utils/event.ts:101-103 CWE-407
F-033 low authorization bypass src/repositories/user-repository.ts:44-44 CWE-862
F-034 low denial of service src/services/notification-channels.ts:42-46 CWE-409
F-036 low authorization bypass src/repositories/user-repository.ts:67-68 CWE-367
F-037 low denial of service src/services/event-import-service.ts:169-172 CWE-409

F-001 — ssrf (low)

src/utils/relay-probe/nip11-probe.ts:96-109

The destination guard rejects selected hostname strings and IP literals but never checks the address used by the HTTP connection. An attacker operating a monitored relay can redirect the probe to a hostname resolving inside the monitoring process's private network.

Evidence

  • Source/control: An HTTP Location header returned by an attacker-operated configured relay, optionally combined with …

Suggested fix. Resolve each initial and redirected destination, reject prohibited IPv4 and IPv6 addresses, and bind the connection to an approved address while preserving the intended Host header and TLS name. Enforce this at connection time so subsequent DNS resolution cannot bypass the check.

F-002 — denial of service (low)

src/services/wot-graph-service.ts:157-164

A contact-list change by an already-trusted author starts a full graph traversal whose breadth depends on previously submitted contact lists. A small update can therefore repeatedly force large Redis reads and graph allocations, consuming shared cache capacity and delaying the relay worker.

Evidence

  • Source/control: Signed kind-3 events from an attacker-controlled account followed by the …

Suggested fix. Enforce explicit node and edge budgets during traversal and bound follow-set reads before materializing their results. Debounce or rate-limit full rebuilds independently of event admission, or update affected graph portions incrementally.

F-003 — denial of service (low)

src/utils/settings-config.ts:493-494

A numeric settings-path index controls a synchronous loop that fills every preceding array position. A short request can therefore require billions of pushes and substantial heap allocation before settings-value validation can reject the resulting configuration.

Evidence

  • Source/control: The path field of an authenticated PATCH /admin/settings request, targeting an array such as dvm.workers …

Suggested fix. Reject indices that are not safe integers and enforce a practical array-size and growth limit before entering the fill loop. Prefer existing-index updates or bounded append operations over filling arbitrary gaps.

F-004 — ssrf (low)

src/utils/nip05.ts:156-171

NIP-05 verification requests a publisher-selected domain without validating its resolved addresses. Redirect validation rejects prohibited address literals but accepts hostnames resolving to the same addresses, allowing an allowed identity endpoint to select a private HTTPS destination, port, and path.

Evidence

  • Source/control: The nip05 field in an accepted signed kind-0 event and a …

Suggested fix. Resolve and reject prohibited destination addresses for initial requests and every redirect, then pin the validated address during connection establishment while retaining hostname-based TLS verification. Apply any required host and port restrictions to redirected destinations as well.

F-005 — authorization bypass (low)

src/services/wot-graph-service.ts:158-164

The graph builder counts repeated follows from one source account as separate supporting followers. When a contact list comes from the database fallback, one trusted author can satisfy a policy requiring several distinct trusted accounts and give a target an undeserved PoW reduction.

Evidence

  • Source/control: Repeated p tags in a valid signed contact-list event authored by an …

Suggested fix. Deduplicate each source account's followed keys before incrementing follower counts. Apply this consistently to database and cached results so each trusted account contributes at most one vote per target.

F-007 — authorization bypass (low)

src/utils/settings.ts:119-122

Publisher admission checks a cached blacklist whose watcher follows only the configuration extension selected at startup. In a JSON-started worker, a successful ban written to settings.yaml does not refresh that blacklist, allowing the banned publisher's otherwise acceptable events to be stored and broadcast.

Evidence

  • Source/control: Valid WebSocket EVENT messages signed by an ordinary …

Suggested fix. Have every worker observe both supported configuration filenames and reload according to YAML precedence. Ensure successful moderation updates refresh the blacklist used by serving workers across the legacy JSON migration.

F-008 — authorization bypass (low)

src/services/wot-graph-service.ts:93-96

The graph cache's ready flag remains valid after hot-reloaded membership settings change. Accounts excluded by the new seed, depth, or follower threshold can retain their previous distance and continue receiving a configured proof-of-work discount.

Evidence

  • Source/control: A signed WebSocket EVENT from an account included in the previously built graph but excluded by the current membership …

Suggested fix. Associate each built graph with its seed, maximum depth, and follower threshold. On a mismatch, withhold cached discounts until a graph for the current settings is available.

F-009 — authorization bypass (low)

src/utils/admin-moderation.ts:272-272

IP bypass revocation compares address text instead of address identity. An administrator can submit a valid equivalent IPv6 spelling and receive success while the client's existing event rate-limit exemption remains active.

Evidence

  • Source/control: The ip field of an authenticated unwhitelist-ip moderation action, including input from the dashboard's Client IP field.
  • Sink/decision: …

Suggested fix. Canonicalize both submitted and stored addresses before comparing them, using the same normalization as client-address enforcement. Normalize existing exemptions as part of removal so older entries are also revoked correctly.

F-010 — authorization bypass (low)

src/services/wot-graph-service.ts:93-97

Each worker reuses its own ready distance map, while accepted contact-list changes trigger rebuilding only in the worker handling the publication. A peer worker can therefore continue granting proof-of-work discounts to an account whose qualifying trust relationships have been removed.

Evidence

  • Source/control: Subsequent signed EVENT messages from a previously trusted account after an …

Suggested fix. Propagate a graph invalidation or shared version whenever an accepted contact-list change affects membership. Require each worker to refresh stale state before granting trust-based discounts.

F-012 — authorization bypass (low)

src/repositories/user-repository.ts:67-68

Initial vanish-state hydration writes a replica-derived negative into the primary users table as permanent authoritative state. An imported vanish request missed during replication lag can consequently remain ineffective even after the replica catches up.

Evidence

  • Source/control: An ordinary signed event for an author whose applicable imported kind-62 request exists on the primary, but …

Suggested fix. Read publication-blocking vanish state from the primary before persisting an initial negative. Reconcile imported vanish requests with user state and preserve concurrently established true flags during initialization.

F-020 — denial of service (low)

src/services/event-import-service.ts:113-117

The importer's deletion-tag collector copies the entire accumulated array for every matching tag. A valid attacker-signed deletion event with repeated references therefore causes quadratic synchronous work and can stall the import process before any referenced-event lookup.

The deletion-target collector copies its growing accumulator for every matching e tag. A signed deletion event with many …

Suggested fix. Collect deletion IDs in one pass using a Set or push, and deduplicate them before database processing. Apply a practical per-event size or tag limit and chunk large database operations.

Replace repeated array spreading with a linear loop that adds identifiers to a Set. Enforce a documented per-event deletion-target limit before persistence to bound subsequent database work.

F-026 — denial of service (low)

src/utils/event.ts:101-103

The live subscription matcher compares every event tag against every criterion in a generic-tag filter synchronously. An attacker can independently enlarge both collections and retain multiple subscriptions, multiplying CPU work on the shared worker event loop.

Generic-tag matching scans all criteria for every event tag until a match is found. An attacker can independently enlarge both inputs …

Suggested fix. Compile exact-match tag criteria into sets and scan event tags without comparing each tag against every value. Bound aggregate matching work, including any remaining prefix comparisons, across each connection's subscriptions.

Index event tags by name and value and use set membership for exact criteria instead of nested scans. Handle prefix matching separately and enforce an aggregate work budget …

F-033 — authorization bypass (low)

src/repositories/user-repository.ts:44-44

Creating an invoice upserts a caller-selected beneficiary using only their public key, but the repository converts omitted admission and vanish flags to false and updates existing accounts with them. An anonymous requester can therefore revoke another user's admission or clear their vanish restriction without owning the key or paying the invoice.

Creating an invoice for a caller-selected public …

Suggested fix. Use an insert-if-absent operation when preparing invoice beneficiaries, leaving existing account fields unchanged. Keep admission and vanish changes in dedicated authorized operations, and make general updates merge only explicitly supplied fields.

Insert the beneficiary only when absent and preserve existing fields on conflict. Change admission and vanish flags only through their dedicated …

F-034 — denial of service (low)

src/services/notification-channels.ts:42-46

HTTP notification delivery automatically decompresses and buffers endpoint responses without limiting their decoded size. A malicious notification endpoint can make a small compressed response consume materially greater memory in the client or maintenance worker, although the application discards the response body.

Evidence

  • Source/control: The HTTP response body and Content-Encoding header …

Suggested fix. Set a small finite maxContentLength on notification requests so Axios aborts oversized decoded responses. Keep the timeout as a separate control.

F-036 — authorization bypass (low)

src/repositories/user-repository.ts:67-68

Lazy vanish-state initialization unconditionally updates an existing row using an earlier event snapshot. If a valid vanish request establishes true after that snapshot, the stale initialization can overwrite it with false and permanently disable the publication restriction.

Evidence

  • Source/control: A forwarded, validly signed ordinary event racing the author's valid vanish request while …

Suggested fix. Initialize missing users with insert-on-conflict-do-nothing, then read and return the authoritative stored flag. Ensure that initialization cannot overwrite a concurrently committed vanish restriction.

F-037 — denial of service (low)

src/services/event-import-service.ts:169-172

The JSONL reader passes unrestricted decompressed input to readline, which accumulates an entire record before validation. A small gzip file containing a highly compressible oversized record can force much larger allocations and abort the importer when memory or string limits are reached.

Compressed JSONL output enters readline without a record-size limit. A highly compressible newline-free …

Suggested fix. Enforce a maximum decoded record size in a streaming transform before readline receives the data. Add a configurable total decoded-byte budget where appropriate, and destroy both source and decompressor immediately when a limit is exceeded.

Enforce a configurable per-record byte limit on decompressed chunks before passing them to readline, and destroy the source and decompressor when exceeded. …


These are grouped by area so one reviewer can judge them together; split any that turn out to need separate work.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    securitySecurity vulnerability or disclosure

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions