Skip to content

Commit 40b36ac

Browse files
Merge pull request #783 from aXenDeveloper/claude/vitnode-security-review-5ly6gw
fix: Security 24 vulnerabilities across auth, rate limiting, and uploads
2 parents 7ca76f4 + 79b5511 commit 40b36ac

405 files changed

Lines changed: 10379 additions & 1954 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/copilot-instructions.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ The repository is a monorepo for the VitNode framework, which includes a backend
1515
- **Frontend:**
1616
- TanStack Start on Vite, file-based routes under `apps/web/src/routes/`
1717
- Navigation: use `@vitnode/core/tanstack/layout`'s `RouterLink`, or TanStack
18-
Router's own `Link` / `useNavigate`. Next.js is not a dependency.
18+
Router's own `Link` / `useNavigate`.
1919
- Forms: Use `react-hook-form@7`, `createServerFn` for mutations
2020
- UI: Shadcn UI, Tailwind CSS 4, dark/light mode with system detection
2121
- i18n: Use `use-intl`, `t('key')` for translations, `createTranslator`

‎apps/api/.env.example‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ REDIS_URL=redis://localhost:6379
44
# Origin of the web application (`apps/web`, `vite dev --port 3000`). This API
55
# trusts it for CORS and CSRF on credentialed browser requests, so a wrong
66
# port here shows up as a blocked upload rather than an obvious error.
7-
NEXT_PUBLIC_WEB_URL=http://localhost:3000
7+
VITNODE_WEB_URL=http://localhost:3000
88
# Public origin of this API. Used to build absolute upload URLs for the Local
99
# storage adapter, so it must match where the server is reachable.
10-
NEXT_PUBLIC_API_URL=http://localhost:8000
10+
VITNODE_API_URL=http://localhost:8000
1111

1212
# === CRON Secret for Internal API Calls ===
1313
CRON_SECRET=your-secure-cron-secret-key

‎apps/api/docker-compose.yml‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ services:
1313
volumes:
1414
- ../../docker/dev:/var/lib/postgresql/data
1515
ports:
16-
- "5432:5432"
16+
# Loopback only - these are development containers with a default password.
17+
- "127.0.0.1:5432:5432"
1718
networks:
1819
- vitnode_dev
1920

@@ -23,7 +24,7 @@ services:
2324
restart: unless-stopped
2425
command: redis-server --requirepass ${REDIS_PASSWORD-root}
2526
ports:
26-
- "6379:6379"
27+
- "127.0.0.1:6379:6379"
2728
networks:
2829
- vitnode_dev
2930

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
WITH normalized AS (
2+
SELECT "id", "email", lower(btrim("email")) AS "normalized" FROM "core_users"
3+
), split AS (
4+
SELECT
5+
"id",
6+
"email",
7+
"normalized",
8+
CASE WHEN length("normalized") - length(replace("normalized", '@', '')) = 1
9+
THEN split_part("normalized", '@', 1) END AS "localPart",
10+
CASE WHEN length("normalized") - length(replace("normalized", '@', '')) = 1
11+
THEN split_part("normalized", '@', 2) END AS "domain"
12+
FROM normalized
13+
), canonical AS (
14+
SELECT
15+
"id",
16+
"email",
17+
CASE
18+
WHEN "localPart" IS NULL OR "localPart" = '' OR "domain" = '' OR left("localPart", 1) = '"'
19+
THEN "normalized"
20+
WHEN "domain" IN ('gmail.com', 'googlemail.com')
21+
THEN CASE
22+
WHEN replace(split_part("localPart", '+', 1), '.', '') = '' THEN "normalized"
23+
ELSE replace(split_part("localPart", '+', 1), '.', '') || '@gmail.com'
24+
END
25+
WHEN "domain" IN (
26+
'fastmail.com', 'fastmail.fm', 'gmx.com', 'gmx.de', 'gmx.net',
27+
'icloud.com', 'mac.com', 'me.com', 'pm.me', 'proton.me',
28+
'protonmail.com', 'yandex.com', 'yandex.ru', 'zoho.com'
29+
) OR "domain" ~ '^(outlook|hotmail|live|msn)\.[a-z]{2,}(\.[a-z]{2,})?$'
30+
THEN CASE
31+
WHEN split_part("localPart", '+', 1) = '' THEN "normalized"
32+
ELSE split_part("localPart", '+', 1) || '@' || "domain"
33+
END
34+
ELSE "normalized"
35+
END AS "canonical"
36+
FROM split
37+
)
38+
UPDATE "core_users" AS u SET "email" = c."canonical"
39+
FROM canonical c
40+
WHERE c."id" = u."id"
41+
AND c."canonical" <> u."email"
42+
AND NOT EXISTS (
43+
SELECT 1 FROM "core_users" taken
44+
WHERE taken."email" = c."canonical" AND taken."id" <> c."id"
45+
)
46+
AND NOT EXISTS (
47+
SELECT 1 FROM canonical rival
48+
WHERE rival."canonical" = c."canonical" AND rival."id" < c."id"
49+
);

0 commit comments

Comments
 (0)