fix(tradein): account-бренд приоритетен над ?brand= — cross-brand leak (#765) #780
No reviewers
Labels
No labels
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
Fable 5 ревью
feedback/max
generative
GG-форсайт
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
вторичка
ИРД
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#780
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "feat/765-brand-account-priority"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
useActiveBrandSlugтеперь отдаёт приоритетme.brand(account binding) над URL-параметром?brand=.?brand=срабатывает только когда у аккаунта нет своего бренда (демо/превью). Обновлён JSDoc.Why (security)
?brand=<slug>безусловно перекрывалme.brand→ любой залогиненный пользователь мог отрендерить чужой бренд (лого/цвета/футер/pdf-дисклеймер) и сгенерировать brand-skinned PDF чужого бренда (чейн с IDOR #690/#710). В prod бренд должен определяться аккаунтом.Test plan
npx tsc --noEmit→ 0 ошибокnpm run build→ ✓ Compiled successfully, 10/10 pagesgetBrandSlugFromUrl()теперь под условием!accountSlug(после проверки account)?brand=acme→ остаётся praktika; demo-юзер без бренда +?brand=praktika→ praktika (qa)Follow-up (вне scope, заведено как замечание)
Backend
/api/v1/brand/{slug}должен дополнительно reject mismatched slug для аккаунта (defense-in-depth) — отдельный backend-issue.Refs #765
✅ APPROVE
Brand cross-leak fix (frontend security #765),
useBrand.ts(содержитuseActiveBrandSlug).Correctness — реализует minimal-safe версию issue дословно:
?brand=URL-param безусловно перевешивалme.brand.accountSlug = me?.brand?.trim().toLowerCase();if (accountSlug) return accountSlug; return getBrandSlugFromUrl(). Account-бренд (server-authoritative из/me) приоритетен;?brand=honored только когда у аккаунта нет бренда (демо/превью).me.brandнепустой →?brand=otherигнорируется → cross-brand leak закрыт (чейн с IDOR #690/#710 brand-skinned PDF).me.brandпустой →?brand=работает (демо не сломано). JSDoc обновлён. DoD:getBrandSlugFromUrlпод!accountSlug✓.Scope/security — только useBrand.ts; нет backend (mismatch-reject — задокументированный follow-up), нет изменения Brand-интерфейса, нет secrets, нет self-extending триггера.
Verdict: ✅ APPROVE (Praktika security #765). Smoke (praktika+
?brand=acme→praktika; demo+?brand=praktika→praktika) → qa.