Skip to content

test(security): deep — JWT tampering, SQLi probes, mass-assignment, IDOR#15

Merged
Br1Im merged 2 commits into
mainfrom
devin/1778711823-tests-security
May 13, 2026
Merged

test(security): deep — JWT tampering, SQLi probes, mass-assignment, IDOR#15
Br1Im merged 2 commits into
mainfrom
devin/1778711823-tests-security

Conversation

@devin-ai-integration

Copy link
Copy Markdown
Contributor

Summary

Глубокие security-тесты — дополнение к существующему security.test.js. 12 новых тестов, всё ходит в реальный MySQL.

73 → 85 backend Jest тестов, прогон полного backend suite: ~38 сек, все ✓.

Что покрыто (server/__tests__/security-deep.test.js)

JWT tampering (4 теста):

  • Самописный alg:none токен (без подписи) → 403
  • Токен с подменённым payload (роль lawyerdirector) при оригинальной подписи → 403 (jwt.verify ловит mismatch)
  • Foreign secret resign (атакер минтит токен своим ключом) → 403
  • Пустой signature segment (header.payload.) → 403

SQL injection probes (3 теста):

  • Логин с классикой SQLi (admin' OR '1'='1, '; DROP TABLE users; --, ' UNION SELECT...) → 4xx, ни один не возвращает токен; таблица users живая
  • Имя клиента с DROP TABLE clients201, значение сохранено литералом (parameterised query), таблица не уронена
  • Числовой :id с SQL-шумом → 4xx/404, таблица clients цела

Mass-assignment guards (2 теста):

  • POST /api/clients с body.office_id = otherOfficeId → клиент создаётся в собственном офисе аттакера (controller перезаписывает office_id из JWT)
  • Регистрация с userType: 'super_admin' → роль НЕ становится director/admin/owner

IDOR / cross-office isolation (2 теста):

  • Юрист офиса A зовёт GET /api/clients → клиенты офиса B отсутствуют в ответе
  • Юрист офиса A с X-Office-Id: <officeB> создаёт /api/cases → дело попадает в A, не B (middleware honours header только для директоров)

Header parsing safety (1 тест):

  • X-Office-Id: 5 OR 1=1; DROP TABLE offices --parseInt отрезает до 5, в SQL уходит safe integer, таблица offices цела

Что добавлено

  • server/__tests__/security-deep.test.js (~270 строк, 12 тестов)
  • TESTING.md — описание security-deep suite

Review & Testing Checklist for Human

  • Локально: cd server && DB_HOST=127.0.0.1 DB_PORT=33307 DB_USER=root DB_PASSWORD=testpass DB_NAME=lawtech_test JWT_SECRET=test_secret npx jest __tests__/security-deep.test.js --runInBand12 passed
  • Полный backend: npm test85 passed (73 старых + 12 новых)
  • CI должен прогнать backend + frontend + E2E + load зелёными

Notes

Что эти тесты НЕ покрывают (могут быть отдельным PR/issue):

  • IDOR на офисах (PUT /api/offices/:id, DELETE /api/offices/:id) — controller не проверяет ownership, любой авторизованный юзер может править/удалить чужой офис. Тест не написан, чтобы не вырывать CI на known vulnerability. Стоит исправить в коде: добавить WHERE owner_id = req.user.id.
  • Rate limiting — в проекте нет express-rate-limit. Без него тестировать нечего. Если введёте — могу написать тесты на 429 при превышении.
  • CSRF / Origin checks — JWT-only API, CSRF не критичен.

Все тесты используют существующие фабрики (registerDirectorWithOffice, registerDirector, registerLawyer) — никаких новых side-effect helpers, кроме локального seedLawyerInOffice для прикрепления юриста к существующему офису.

Link to Devin session: https://app.devin.ai/sessions/514f368ad0194bf18d0327e62a88aeda
Requested by: @Br1Im

12 new tests in server/__tests__/security-deep.test.js, complementary to
the existing security.test.js (3 JWT + X-Office-Id + auth-gate tests).

JWT tampering:
- alg:none unsigned token → 403
- payload-only modification (lawyer→director) → 403 (signature mismatch)
- foreign secret re-sign → 403
- missing signature segment → 403

SQL injection probes (parameterised queries hold up):
- login with classic SQLi payloads → 4xx, no token issued
- SQLi-laced client name → stored literally, table intact
- numeric id with SQL noise → 4xx, no data leak

Mass-assignment guards:
- body.office_id ignored on POST /api/clients (uses JWT office_id)
- registering with userType=super_admin never grants director/admin role

IDOR / cross-office isolation:
- lawyer in office A sees no office B clients via GET /api/clients
- lawyer cannot spoof office via X-Office-Id (middleware honours only directors)

Header parsing safety:
- X-Office-Id 'N OR 1=1; DROP TABLE...' → parseInt → safe integer, no SQLi

73 → 85 backend Jest tests, all green.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

…onflict

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
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.

1 participant