Files
summercms/.planning/phases/14.2.1-translate-plugin/14.2.1-SECURITY-REVIEW.md
Jakub Zych 249b4d10ca docs(14.2.1-04): complete translate tests, gate, and security review
Record the last-plan SUMMARY, closed high-threat review, validation sign-off, and 4/4 roadmap progress.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-06 14:23:06 +02:00

13 KiB
Raw Blame History

phase, slug, status, threats_total, threats_closed, threats_open, accepted_risks, asvs_level, created, verified, reviewer
phase slug status threats_total threats_closed threats_open accepted_risks asvs_level created verified reviewer
14.2.1 translate-plugin verified 19 19 0 0 1 2026-10-06 2026-10-06 gsd-executor (14.2.1-04 Task 3, self-performed -- see Reviewer Note)

Phase 14.2.1 — Security Review

Lean Translate plugin (sm-translate-plugin), cabana markdown/mltext/mlmarkdown, surf LocaleResolver, and the proof-host boot of user+translate. Every T-14.2.1 threat locked in plans 01–04 is mapped below to executed, named Go or Vitest evidence. Unmapped IDs would be a review gap, not an accepted risk; none exist.

Date: 2026-10-06 Scope: Plans 14.2.1-01 through 14.2.1-04; sm-translate-plugin; summercms.go modules cabana and surf plus admin SPA ML/markdown controls; proof host sm-grzybyfunkcjonalne-app. Repos grepped: sm-translate-plugin, summercms.go (excluding .planning/ except this review), sm-grzybyfunkcjonalne-app.

Reviewer Note

14.2.1-04-PLAN.md Task 3 calls for an independent gsd-security-auditor agent pass. This Cursor session has no dedicated security-auditor subagent (same fallback as Phase 08): the 14.2.1-04 executor performed the review directly. Every high threat below is closed with source citations and named tests re-executed during this review (2026-10-06), not merely inherited from earlier plans. The executor checkpoint return states this plainly.

No external API integration: this phase ports a compiled plugin and local framework/host contracts only.


Verdict Summary

The register contains 19 total threats: 19 closed, 0 open, 0 accepted risks. High findings block phase completion; all high rows are mitigate with executed named tests. PHP pin SHA 725d547ec839f02b5fdc0f0a6faaed601a414d50 is unchanged.


Trust Boundaries

Boundary Description Data Crossing
untrusted request → Translator URL prefix, cookies, Accept-Language, principal preferred_locale locale codes only; must match enabled Locale rows
unauthenticated vs manage_locales Locales admin CRUD JWT + permission grant
admin SPA → cabana save nested mltext/mlmarkdown JSON locale→string maps lifted before Fill
markdown source → HTML stored body / SPA preview goldmark without WithUnsafe; SPA interpolates text
test fixture → production binary process-local acme.fixture must not appear in generated plugin imports
gate → production claims skipped containers / stale dist named PASS + final marker

Threat Register

Threat ID Category Component Severity Disposition Proof
T-14.2.1-01 Tampering Translator locale inputs high mitigate classes/translator_resolve_test.go:TestTranslatorResolve (URL/session/header invalid codes ignored; only enabled en/pl)
T-14.2.1-02 Information Disclosure request locale state high mitigate classes/translator.go has no process singleton; TestTranslatorConcurrentIsolation; modules/surf/locale_resolver_test.go:TestLocaleResolver
T-14.2.1-03 Tampering manual-selection cookie medium mitigate classes/translator_test.go:TestManualFlagIsNotALocale; TestTranslatorResolve/manual_flag_blocks_accept-language
T-14.2.1-04 Tampering schema source high mitigate updates/migrations_test.go:TestTranslateTables; TestTranslateMigrationsRollbackAndRemigrate; no AutoMigrate in production plugin
T-14.2.1-05 Elevation of Privilege Locales admin high mitigate locales_admin_test.go:TestLocalesAdminForbidden; integration_test.go:TestTranslateEndToEnd 403 without golem15.translate.manage_locales
T-14.2.1-06 Tampering Locale writes high mitigate models/locale.go Fillable excludes is_default/sort_order; TestLocalesAdminMassAssignment; TestLocalesAdminDefaultGuards
T-14.2.1-07 Tampering SetTranslated high mitigate classes/translatable.go declared-field + enabled-locale checks; TestInvalidLocaleRejected; TestTranslatableGetSet
T-14.2.1-08 Information Disclosure Morph/index queries medium mitigate TestTranslatableIndexAndMorphIsolation; MorphName is an import-stable string
T-14.2.1-09 Tampering ML nested request high mitigate modules/cabana/field_ml.go liftMLValues; TestMLNestedSave; TestMLFieldTypes
T-14.2.1-10 Elevation of Privilege TranslationWriter high mitigate no standalone translate-write route; TestML/writer_is_not_invoked_before_query_checks; writer runs after host PK inside the save transaction
T-14.2.1-11 Tampering mass assignment high mitigate nested non-ML maps still dropped; default scalar only reaches Fill; TestMLNestedSave
T-14.2.1-12 Tampering markdown preview high mitigate modules/cabana/field_markdown.go:RenderMarkdown; TestMarkdownRejectsUnsafeHTML; admin/tests/form/MarkdownField.test.ts
T-14.2.1-13 Tampering host submodule provenance medium mitigate TestBootUserTranslate gitlink 160000; scripts/check-phase14.2.1.sh --layout
T-14.2.1-14 Repudiation phase gate high mitigate scripts/check-phase14.2.1.sh detector refuses skip/no-tests/race; --self-test proves fail-closed
T-14.2.1-15 Information Disclosure concurrent Translator high mitigate TestTranslatorConcurrentIsolation under go test -race; TestLocaleResolver/conflicting_requests_stay_isolated
T-14.2.1-16 Tampering migration rollback medium mitigate TestTranslateMigrationsRollbackAndRemigrate dedicated Postgres
T-14.2.1-17 Tampering generated admin artifacts medium mitigate TestMLOpenAPIConformance; scripts/check-admin-openapi.sh --check; scripts/check-admin-dist.sh
T-14.2.1-18 Elevation of Privilege test fixture high mitigate TestTranslateEndToEndFixtureAbsentFromProduction; host plugins.gen.go has no acme.fixture
T-14.2.1-SC Tampering package installs high mitigate no go get / npm install this plan; plugin replace of sm-user-plugin is a sibling checkout; framework go.mod/admin/package-lock.json unchanged

Findings by Threat

T-14.2.1-01 — locale injection

  • Source: sm-translate-plugin/classes/translator.go isValid / enabledCodes (enabled Locale rows only).
  • Test evidence (re-run 2026-10-06): TestTranslatorResolve subtests invalid_url_session_and_header_ignored, url_prefix_wins_and_strips, accept-language_reduced_to_enabled_codes — PASS.
  • Disposition: closed / mitigate.

T-14.2.1-02 — process-wide locale leak

  • Source: Translator.Locale reads towel.Locale(ctx) only; no package-level current locale.
  • Test evidence (re-run 2026-10-06): TestTranslatorConcurrentIsolation PASS; TestLocaleResolver isolation subtest PASS; plugin go test ./... -race PASS.
  • Disposition: closed / mitigate.
  • Source: hasManualFlag treats any non-empty value as a flag; rememberedLocale reads a different cookie name.
  • Test evidence (re-run 2026-10-06): TestManualFlagIsNotALocale (package classes); TestTranslatorResolve/manual_flag_blocks_accept-language PASS.
  • Disposition: closed / mitigate.

T-14.2.1-04 — schema / AutoMigrate

  • Source: gormigrate files updates/202610060001–005; plugin production Go has no AutoMigrate.
  • Test evidence (re-run 2026-10-06): TestTranslateTables, TestSeedEnPl, TestTranslateMigrationsRollbackAndRemigrate PASS. Gate --forbidden refuses production AutoMigrate.
  • Disposition: closed / mitigate.

T-14.2.1-05 — manage_locales privilege

  • Source: controllers/locales.go RequiredPermissions = golem15.translate.manage_locales.
  • Test evidence (re-run 2026-10-06): TestLocalesAdminForbidden PASS; TestTranslateEndToEnd 403 on list/schema without the grant PASS.
  • Disposition: closed / mitigate.

T-14.2.1-06 — Locale mass assignment and default lifecycle

  • Source: models/locale.go Fillable is code,name,is_enabled; FormBeforeDelete / FormBeforeUpdate / makeDefault.
  • Test evidence (re-run 2026-10-06): TestLocalesAdminMassAssignment, TestLocalesAdminDefaultGuards covered by the plugin suite (smoke + full admin tests) PASS in go test ./....
  • Disposition: closed / mitigate.

T-14.2.1-07 — undeclared field / invalid locale writes

  • Source: classes/translatable.go validateCall.
  • Test evidence (re-run 2026-10-06): TestInvalidLocaleRejected, TestTranslatableGetSet PASS.
  • Disposition: closed / mitigate.

T-14.2.1-08 — morph/index isolation

  • Source: WhereIndex predicates on model_type, locale, item, value.
  • Test evidence (re-run 2026-10-06): TestTranslatableIndexAndMorphIsolation in the plugin ./... suite PASS.
  • Disposition: closed / mitigate.

T-14.2.1-09 — nested ML JSON

  • Source: modules/cabana/field_ml.go liftMLValues (enabled locale codes, string values, default required).
  • Test evidence (re-run 2026-10-06): TestMLFieldTypes, TestMLNestedSave PASS.
  • Disposition: closed / mitigate.

T-14.2.1-10 — TranslationWriter privilege

  • Source: cabana.TranslationWriter comment and crud.go save: apply after Create/Update, after permission/query/lock checks.
  • Test evidence (re-run 2026-10-06): TestML/writer_is_not_invoked_before_query_checks, TestML/writer_failure_rolls_back_host_write PASS.
  • Disposition: closed / mitigate.

T-14.2.1-11 — ML mass assignment

  • Source: lift before ProjectWritableFields; extra nested keys stay blocked.
  • Test evidence (re-run 2026-10-06): TestMLNestedSave PASS (unlifted nested maps empty; extra locale de rejected).
  • Disposition: closed / mitigate.

T-14.2.1-12 — stored XSS / markdown

  • Source: RenderMarkdown goldmark without html.WithUnsafe; rejects script/iframe/event/javascript/vbscript/data. SPA preview interpolates text, no v-html=.
  • Test evidence (re-run 2026-10-06): TestMarkdownRejectsUnsafeHTML (script/iframe/event/javascript/vbscript/data) PASS; Vitest tests/form/MarkdownField.test.ts 3/3 PASS.
  • Disposition: closed / mitigate.

T-14.2.1-13 — submodule provenance

  • Source: host gitlinks plugins/golem15/{user,translate}.
  • Test evidence (re-run 2026-10-06): TestBootUserTranslate PASS; --layout PASS.
  • Disposition: closed / mitigate.

T-14.2.1-14 — gate repudiation

  • Source: scripts/check-phase14.2.1.sh JSON detector.
  • Test evidence (re-run 2026-10-06): --self-test PASS (fail/skip/zero/no-tests/race/missing-named).
  • Disposition: closed / mitigate.

T-14.2.1-15 — concurrent Translator

  • Source: context-only locale; Rewrite clones the request.
  • Test evidence (re-run 2026-10-06): TestTranslatorConcurrentIsolation PASS; plugin -race PASS; TestLocaleResolver/conflicting_requests_stay_isolated PASS.
  • Disposition: closed / mitigate.

T-14.2.1-16 — migration rollback

  • Source: gormigrate RollbackLast ×5 then remigrate on a dedicated database.
  • Test evidence (re-run 2026-10-06): TestTranslateMigrationsRollbackAndRemigrate PASS.
  • Disposition: closed / mitigate.

T-14.2.1-17 — generated artifacts

  • Source: committed admin/openapi/admin.json, schema.d.ts, modules/boardwalk/dist.
  • Test evidence: TestMLOpenAPIConformance PASS (re-run 2026-10-06); gate --admin regenerates and diffs.
  • Disposition: closed / mitigate.

T-14.2.1-18 — test fixture in production

  • Source: party.Register of acme.fixture is sync.Once inside tests only.
  • Test evidence (re-run 2026-10-06): TestTranslateEndToEndFixtureAbsentFromProduction matched by TestTranslateEndToEnd* in the plugin ./... run PASS; host plugins.gen.go lists only golem15.user and golem15.translate.
  • Disposition: closed / mitigate.

T-14.2.1-SC — package installs

  • Source: no new module versions beyond existing stack pins; plugin replace of sm-user-plugin points at the host submodule checkout; gocloud.dev v0.46.0 is the already-decided blob pin. Framework go.mod / admin/package-lock.json were not changed in this phase.
  • Test evidence: git log -- go.mod go.sum on the framework shows no 14.2.1 commits; plugin go.mod Task 1 added a local replace, not a downloaded package.
  • Disposition: closed / mitigate.

Deferred surfaces confirmed absent

Gate --forbidden (re-run 2026-10-06, PASS) refuses production manage_messages, plugin.Open/yaegi, plugin AutoMigrate, acme.fixture outside tests, Winter/RainLab table names in production Go, consuming-application names in framework docs, and v-html= in admin/src.


ASVS L1 mapping (selected)

ASVS Control Evidence
V4.1 Access control on admin TestLocalesAdminForbidden
V5.1.3 Mass assignment Locale Fillable + ML lift
V5.2 Sanitization / XSS RenderMarkdown + SPA text interpolation
V11.1 Stored locale injection enabled-row validation
V14.2 Dependency integrity T-14.2.1-SC

Approval: closed — all high threats mitigated with re-executed named tests.