Skip to content

Automated shortlink abuse screening & moderation controls#3

Draft
navi-crwn wants to merge 1 commit into
mainfrom
claude/code-audit-fixes-1v4p4n
Draft

Automated shortlink abuse screening & moderation controls#3
navi-crwn wants to merge 1 commit into
mainfrom
claude/code-audit-fixes-1v4p4n

Conversation

@navi-crwn

Copy link
Copy Markdown
Owner

Why

A real incident prompted this: an anonymous visitor used the shortener to distribute illegal (CSAM) content, and the registrar contacted the operator as the apparent distributor. On a free-to-use service that isn't monitored around the clock, takedown can't depend on someone watching a dashboard. This PR adds layered, automated abuse defenses so bad links are caught at creation and are quick to action.

What

Screening at creation (LinkScreeningService + ScreensLinks trait)

Applied to every creation path — anonymous public, API, and dashboard:

  1. Admin domain blacklist → hard block (reuses existing DomainBlacklist)
  2. Google Safe Browsing → hard block on known malware/phishing/unwanted-software (opt-in; no-op unless SAFE_BROWSING_API_KEY is set; fails open on upstream errors)
  3. Keyword heuristicflag for review by default (or block), whole-word matching with plural handling, tuned to avoid false positives (verified: pediatrics/childcare/pedometer do not trip)

All behavior is config-driven in config/abuse.php and overridable via env — the operator tunes the keyword list, the flag-vs-block posture, and allowlisted hosts.

Moderation & takedown

  • New flagged link status (non-redirecting, held for review) with flagged_at / flag_reason, plus created_ip recorded on all links for forensics on anonymous abuse (migration + Link model).
  • Email alert to the security address on every auto-block/flag, so action doesn't require live monitoring.
  • Auto-flagged links are reviewable in admin via ?status=flagged; approving one clears its flag.
  • One-click takedown on the abuse-report screen: disable the reported link and/or blacklist its domain.
  • "Report this link" now surfaced on the redirect interstitial and the 404 page (previously the report flow was unreachable from any visitor-facing page).

Cleanup

  • Archived unused views — the duplicate/half-migrated bio editor (bio/edit.blade.php + bio/partials/*) and two orphan maintenance views — into a single compressed backup at archive/unused-20260702.tar.gz, and removed them from the live tree (~3.9k lines). Restore instructions are in the archive's README.

Migration

Adds created_ip, flagged_at, flag_reason to links — run php artisan migrate.

Config / setup

New keys in .env.example (all optional; screening works out of the box with the built-in keyword net):

ABUSE_SCREENING_ENABLED=true
ABUSE_HEURISTIC_ACTION=flag        # or "block"
ABUSE_NOTIFY_ON_FLAG=true
SAFE_BROWSING_API_KEY=             # enables the Safe Browsing layer
ABUSE_KEYWORDS=                    # comma-separated overrides
ABUSE_KEYWORD_ALLOWLIST_HOSTS=

Testing

  • php -l passes on all changed PHP.
  • The keyword heuristic was exercised against a matrix of CSAM-variant URLs (obfuscated separators, plurals) and legitimate look-alikes; all matched/spared as intended.
  • No vendor/ in this environment, so the PHPUnit suite couldn't run here.

Notes / follow-ups

  • The keyword heuristic is a coarse triage aid, deliberately conservative — not a substitute for the abuse-report channel or any legal reporting obligations. Expand the list for your risk profile.
  • Enabling SAFE_BROWSING_API_KEY is strongly recommended; it adds authoritative malware/phishing coverage the keyword net can't provide.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Lnoi65hsXRNZWtdWPSGDbe


Generated by Claude Code

Motivated by a real incident: an anonymous user shortened a link to
illegal (CSAM) content, exposing the operator to registrar/takedown
action on an unmonitored, free-to-use service. Adds layered, automated
defenses so abuse is caught and actioned without live monitoring.

Screening (app/Services/LinkScreeningService.php), applied on every
creation path (public/anonymous, API, dashboard) via a shared
ScreensLinks trait:
- Admin domain blacklist  -> hard block
- Google Safe Browsing    -> hard block on known threats (opt-in via key)
- Keyword heuristic        -> flag for review (default) or block
Verdicts are config-driven in config/abuse.php and fully tunable.

Moderation:
- Record creator IP on all links; add a non-redirecting "flagged" status
  with flagged_at/flag_reason (migration + Link model).
- Email the security address on every auto-block/flag (notify_on_flag).
- Admins can review auto-flagged links (?status=flagged); approving one
  clears its flag.
- One-click takedown from the abuse report screen: disable the reported
  link and/or blacklist its domain.
- Surface "Report this link" on the redirect interstitial and 404 page.

Cleanup: archive unused views (duplicate half-migrated bio editor
bio/edit + bio/partials/*, and orphan maintenance views) into a single
compressed backup at archive/unused-20260702.tar.gz and remove them from
the live tree.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lnoi65hsXRNZWtdWPSGDbe
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants