Актуализировано 2026-09-30; browser roles — accounts-panel.md, окружения и DB roles — environments.md.
Модель охватывает job-agent: FastAPI/admin/MCP, Celery/Beat, crawler adapters,
PostgreSQL, Redis, storage резюме, LLM providers, Gmail OAuth/API, reverse proxy и
операционные процессы.
Цели безопасности:
- никто не отправляет письмо без явной пользовательской политики и hard rules;
- одна логическая Application не отправляется дважды;
- недоверенный сайт/LLM не получает secrets и не управляет системой;
- crawler не становится SSRF-прокси во внутреннюю сеть;
- профиль, Resume, контакты и OAuth-токены сохраняют конфиденциальность;
- история вакансий, решений, отправок и аудит сохраняют целостность;
- деградация источника не вызывает массовых опасных действий;
- сервис остаётся управляемым через pause/disable/recovery.
Модель пересматривается при добавлении источника/provider, изменении auth, включении новой формы отправки, расширении scope или крупном изменении deployment.
- Gmail refresh/access token и OAuth client secret;
- право отправлять письмо от имени пользователя;
- профиль, подтверждённые факты и preferences;
- PDF-резюме и storage keys;
- EmployerContact и Application content;
- SourceJob/CanonicalJob/Snapshots/MatchEvaluation;
- policy versions, idempotency keys и delivery status;
- admin sessions, MCP credentials и encryption keys;
- PostgreSQL/backup/audit log;
- availability worker/scheduler/source capacity;
- репутация пользователя и соблюдение условий источников.
- злоумышленник, публикующий вакансию с prompt injection/scam;
- контролируемый им сайт/redirect/DNS;
- внешний неаутентифицированный web/MCP-клиент;
- пользователь с отозванным/невалидным token или с ролью внешнего gateway, пытающийся повысить права;
- скомпрометированный admin/MCP credential;
- недобросовестный или ошибающийся оператор;
- уязвимая/скомпрометированная зависимость или CI action;
- случайный отказ Gmail/LLM/job board/сети;
- изменение HTML/access policy без злого умысла;
- другой tenant/процесс на общем хосте, если deployment не изолирован.
Google, LLM provider, облачная платформа и job boards считаются внешними зависимостями, а не полностью доверенными внутренними компонентами.
- production host, DNS и secret manager администрируются компетентным оператором;
- пользователь имеет право применять загруженные Resume и подключённый Gmail;
- сервер синхронизирует время;
- TLS private key не скомпрометирован;
- PostgreSQL обеспечивает требуемые транзакции/constraints;
- публичная доступность данных не заменяет юридическую проверку их использования;
- browser accounts изолируются серверными owner/profile checks; общий каталог источников и операторский bearer остаются общими привилегированными областями. User isolation не превращает REST/MCP bearer в tenant-scoped credential.
Нарушение предположения требует отдельной архитектурной проверки.
Internet job sources (untrusted)
│ HTML/API/URLs
▼
Crawler boundary ──► normalized SourceJob ──► DB
│
Profile/Resume ──► matching ──► LLM boundary │
│ validated result │
▼ │
verified contact ─► application ─► policy ──┤
▼
Admin / MCP ─authn/authz/audit─► services ─► Celery/Redis
│ application_id
▼
Gmail provider ─► Google
Границы пересекают также OAuth browser redirect, upload PDF, Caddy, backup и CI.
| ID | Угроза | Последствие | Основные меры | Остаточный риск |
|---|---|---|---|---|
| T1 | Prompt injection в вакансии | изменение поведения, утечка, неверная отправка | data envelope, LLM без tools/secrets, strict schema, deterministic policy, injection tests | модель может не распознать новую формулировку; hard rules ограничивают impact |
| T2 | Scam/поддельный контакт | письмо мошеннику, утечка Resume | verified public contact, official-domain/evidence, scam rules, review | официальный домен/страница тоже могут быть скомпрометированы |
| T3 | SSRF через URL/redirect | metadata/internal service access | allowlist, DNS/IP/peer validation, redirect checks, egress firewall | сложные DNS/proxy ошибки требуют постоянных тестов |
| T4 | Path traversal/вредный PDF | чтение/запись файла, parser exploit | random storage key, root containment, MIME/magic/size, no execution, optional AV | zero-day PDF parser/storage layer |
| T5 | Кража OAuth token | отправка от имени пользователя | minimal gmail.send, authenticated encryption одним key вне БД, redaction, revoke | компрометация runtime с decrypt key позволяет использование; key ring отсутствует |
| T6 | Повторная отправка/race | репутационный ущерб | CanonicalJob uniqueness, idempotency key, DB CAS, locks, delivery record | timeout после provider acceptance требует manual reconciliation |
| T7 | Превышение дневного лимита | массовая отправка | atomic slot reservation, sending/unknown учитываются, final check | неверный timezone/config; нужен audit/alert |
| T8 | Подмена recipient/attachment | утечка/неверное письмо | sender принимает только application_id, server loads verified records | компрометация БД/admin остаётся высокорисковой |
| T9 | Broken adapter массово закрывает jobs | потеря вакансий/ошибочные решения | degradation circuit breaker, absence threshold, snapshots, no mass close | медленный частичный drift может обойти baseline |
| T10 | Обход auth/CSRF | изменение политики/отправка | admin/user session, ownership checks, CSRF, privileged bearer, process-local limiter; gateway для bearer scopes/distributed limits | stolen admin session или bearer до отзыва/restart |
| T11 | MCP tool abuse | scan DoS, policy/source changes, send attempts | hashed bearer allowlist, schemas, audit, server policy; optional scoped/rate-limiting gateway | встроенный ключ имеет доступ ко всем tools и должен считаться привилегированным |
| T12 | XSS через HTML/filename/error | кража admin session | escaping/sanitizer, CSP, safe headers/filenames | sanitizer/browser bypass |
| T13 | SQL/command/template injection | DB/host compromise | parameterized ORM, no shell transforms, strict config, sandboxed containers | уязвимость зависимости/новый unsafe code path |
| T14 | Secrets в логах/CI/backup | долгосрочная компрометация | structured redaction, secret scanning, protected backup, least privilege | operator copy/screenshot вне системы |
| T15 | Queue message tampering/replay | повтор операции/устаревшая policy | tasks carry IDs, DB reload/final check, idempotency, broker auth | compromised DB/runtime выходит за эту границу |
| T16 | Dependency/CI compromise | backdoor, secret theft | lockfile, audits, pinned actions, minimal CI perms, image scan | trusted upstream compromise |
| T17 | DoS источником/клиентом | недоступность и расходы | size/time/page/concurrency limits, process-local HTTP limiter, queue isolation, circuit breakers; внешний distributed limiter | распределённый low-rate DoS и обход лимита через несколько процессов |
| T18 | Неверный LLM JSON/галлюцинация | ложная оценка/факт | strict Pydantic, bounded retry, confirmed-fact validation, manual fallback | качественная, но неверная оценка остаётся возможной |
| T19 | Access policy/terms change | юридический/технический риск | source pause, ручная периодическая проверка terms, documented limitations | автоматического terms hash/change detector нет; ручная проверка не заменяет юриста |
| T20 | Backup/restore compromise | утечка или потеря данных | Compose dump/checksum/restore guard; внешние encryption, off-host copy, retention и restore drills | поставляемый named volume остаётся на одном host и не шифруется автоматически |
| T21 | Telegram post-call notification intercept или duplicate после crash | утечка summary/link, повторная карточка | HTTPS only, fixed host, no redirects, bounded retry, ambiguous transport terminal, revision/lease claim, privacy-aware rendering, отключено по умолчанию, sidecar fail не влияет на call handling, токен хранится как SecretStr | compromised Telegram account или bot; unavoidable crash-after-response window из-за отсутствия Telegram idempotency key; утечка внутренних application ID через link |
Пример: описание требует игнорировать правила, взять /etc/passwd вместо Resume,
изменить адрес и вызвать send_application дважды.
Контроль:
- crawler сохраняет это как plain text;
- matcher получает недоверенный data block и не имеет tools/filesystem;
- output schema не содержит recipient/path/preferences;
- application generator выбирает Resume по verified ID/category;
- contact layer выбирает verified EmployerContact;
- policy блокирует injection indicator;
- sender принимает только сохранённый application ID;
- unique constraints/locks не дают повтор.
Security test должен проверять отсутствие side effects, а не только decision text.
Пример: employer link ведёт на http://169.254.169.254/ либо public host делает
redirect на 127.0.0.1/AAAA ::1.
Контроль: scheme/host allowlist, resolve всех A/AAAA, special-use deny, повторная проверка redirect и actual peer, egress firewall. URL отклоняется до получения body; ошибка фиксируется без секретного response.
Тесты включают decimal/hex/IPv4-mapped IPv6, userinfo, trailing dot, DNS answer с несколькими IP и redirect chain.
Host сначала resolves в public IP, затем во внутренний. Раздельная «проверка, а потом обычный connect» уязвима. Fetcher должен соединяться с проверенным IP с корректным TLS SNI/Host или сравнивать фактический peer; DNS TTL и connection pool не должны обходить validation. Network egress deny остаётся второй границей.
Broker повторно доставляет send task после worker crash. Task содержит только
application ID. Новый worker открывает transaction, видит sending/EmailDelivery,
проверяет idempotency. Если неизвестно, был ли provider вызван, переходит/оставляет
delivery_unknown, не отправляет повторно.
Пользователь включает global pause или запрещает категорию после auto_approved.
Worker перечитывает текущие preferences/emergency switch и пересчитывает hard
rules перед Gmail call. Старое решение не является capability token.
Recheck parser перестал видеть активный marker, многие страницы одновременно «пропали». Health evaluator замечает correlated anomaly/parsing errors и включает circuit breaker. Absence counters не увеличиваются; источник paused/degraded, другие продолжают работу.
Встроенный bearer key является привилегированным и позволяет вызывать write tools; server-side policy по-прежнему запрещает произвольного получателя, вложение и обход лимитов, но атакующий может менять профиль/источники и запускать допустимые операции. Process-local rate limit, audit и удаление hash из конфигурации с перезапуском API ограничивают ущерб. Для разных уровней доступа или распределённых лимитов обязателен scoped identity gateway либо отдельная scoped-key реализация.
Технически привилегированный оператор может изменить preferences/contact state или получить Resume. Меры: минимальные роли, MFA/identity provider, append-oriented audit, разделение deployment secret и app admin, alerts на включение real-send и смену contact/policy. Полностью устранить риск без организационного контроля и multi-party approval нельзя.
- Spoofing: credential theft → secure session, hashed bearer allowlist, operator-managed revoke/restart; встроенных bearer scopes нет.
- Tampering: CSRF/parameter manipulation → CSRF, schemas, audit и admin/user ownership checks. Read/write scopes для bearer требуют внешнего gateway или отдельной серверной модели; browser role не создаёт bearer scope.
- Repudiation: отрицание approve/send → actor/correlation AuditEvent.
- Information disclosure: over-broad responses → field-level minimization/redaction.
- Denial of service: scans/large uploads → rate/body/task limits.
- Elevation: якобы read-only key вызывает write → любой встроенный bearer уже имеет все tools; реальное разделение обеспечивается только gateway/scoped-key расширением.
- Spoofing: fake employer/source → configured source identity/TLS/allowlist.
- Tampering: HTML/structured payload → strict parser/normalization/snapshots.
- Repudiation: источник меняет content → hash/snapshot/timestamps, не юридическая non-repudiation.
- Disclosure: SSRF → IP/redirect/egress controls.
- DoS: infinite pagination/huge body → max pages/body/time/concurrency.
- Elevation: YAML transform executes code → declarative allowlisted transforms.
- Spoofing/tampering: injection/invalid JSON → isolation/schema/confirmed facts.
- Repudiation: модель/правила неизвестны → model, prompt/rules/policy version.
- Disclosure: excess PII in prompt → minimization, no secrets/full Resume unless strictly needed and approved provider policy.
- DoS: oversized vacancy/retries → truncation/token/retry bounds.
- Elevation: LLM decision becomes send → deterministic hard rules.
- Spoofing: stolen token → AEAD/minimal scope/revoke.
- Tampering: recipient/MIME arguments → application-ID-only boundary.
- Repudiation: unknown provider result → EmailDelivery/message id/audit.
- Disclosure: wrong attachment/log → server selection, SHA-256, redaction.
- DoS: quota/429/revocation → bounded backoff/alert/reconnect.
- Elevation: queue task skips policy → final reload/check/transaction.
- Spoofing: service credentials → network isolation/unique credentials.
- Tampering: direct DB/queue → constraints, least privilege, DB-as-truth.
- Repudiation: audit modification → append-oriented schema; отдельная DB role и внешний immutable log sink не входят в текущий Compose и добавляются при требуемом уровне защиты.
- Disclosure: volume/backup theft → host access controls; encryption/off-host retention должен настроить оператор.
- DoS: disk/queue exhaustion → quotas/alerts/backpressure.
- Elevation: migration/runtime credential слишком широк → PROD Compose разделяет
jobhunter_appиjobhunter_migratorи проверяет роль при старте. Базовый DEV credential не используется как production runtime credential.
Даже без классической атаки возможны:
- отправка чрезмерного объёма профиля LLM/provider;
- хранение вакансий/контактов/резюме дольше цели;
- раскрытие PII в daily report/metrics;
- межпользовательское смешение данных из-за пропущенной owner/profile проверки в новом route, worker или Gmail path;
- использование публичного личного email вне цели публикации.
Меры: data minimization, purpose limitation, field-level auth, retention/delete workflow, no PII metric labels, owner/profile checks в каждом browser action, account-scoped Gmail credential/cursor, background lifecycle gates и negative изоляционные тесты; review contact purpose/evidence.
Компонент должен отказывать безопасно:
- PostgreSQL недоступен → нет policy/send; health not ready;
- Redis недоступен → scheduler/queue остановлены, прямой обход locks запрещён;
- LLM invalid/unavailable → pending review, не auto-send;
- Gmail timeout ambiguous → delivery unknown, no retry;
- source degraded → source pause, no mass close/applications;
- encryption key недоступен → Gmail disabled, token не удаляется;
- audit write failed для privileged action → операция fail closed там, где это предусмотрено требованиями целостности.
- Ни HTML parser, ни LLM не гарантируют распознавание всех scam/injection.
- Official website/contact может быть скомпрометирован.
gmail.sendвсё ещё позволяет отправлять почту; компрометация runtime вместе с ключом расшифрования критична.- Provider acceptance не гарантирует доставку/прочтение;
sentозначает подтверждённый API result, не человеческую доставку. - Semantic dedup может ошибочно объединить или разделить вакансии; merge обратим, но неверный merge может блокировать второй отклик.
- Условия сайта и право меняются; техническая реализация не является юридическим заключением.
- Привилегированный оператор и любой валидный REST/MCP bearer сохраняют высокий insider risk даже при изолированных browser user accounts.
- Docker/host root может читать процессы, volumes и secrets.
- Backup с PII остаётся чувствительным даже после удаления live-записи до истечения retention.
Автоматические тесты:
- SSRF IPv4/IPv6/redirect/DNS/metadata;
- upload size/MIME/magic/path traversal;
- HTML escaping и CSRF/authz;
- strict LLM JSON и bounded fallback;
- prompt injection side-effect assertions;
- verified facts/contact/resume;
- policy rules, pause, emergency switch, daily limit;
- concurrent idempotency и duplicate canonical job;
delivery_unknownno retry;- recheck transition/degradation circuit breaker;
- MCP bearer revoke/audit и, при необходимости, role separation во внешнем gateway;
- fake Gmail only в CI.
Ручные/операционные проверки:
- OAuth consent/scope/redirect и revoke;
- egress firewall/metadata denial из контейнера;
- reverse proxy headers/streaming/origin;
- restore drill и encryption key recovery;
- emergency pause во время queued send;
- source policy review/live opt-in smoke;
- secret leak exercise и credential rotation;
- audit review/alert delivery.
Владелец deployment ведёт risk register с полями: ID, описание, актив, вероятность/impact, controls, test evidence, owner, due date, accepted residual risk и дата пересмотра. High-impact исключение без владельца и срока не допускается.
После инцидента или существенного изменения обновляются одновременно threat model, security tests и runbook, а не только текст документа.