Skip to content

Security harden 2 - #155

Open
cruzzer wants to merge 3 commits into
anuko:masterfrom
cruzzer:security-harden-2
Open

Security harden 2#155
cruzzer wants to merge 3 commits into
anuko:masterfrom
cruzzer:security-harden-2

Conversation

@cruzzer

@cruzzer cruzzer commented Sep 8, 2026

Copy link
Copy Markdown

2nd harden commit.

cruiser added 3 commits September 4, 2026 20:35
I18n::get() assembled a fragment of PHP source from a translation key
and ran it through eval() to reach a nested value; load() did the same
on the write side, three more times. Replace all four with a plain array
walk, which is what the generated code was doing anyway.

Deriving code from data makes the lookup depend on keys being well
formed in ways the dotted notation never promised, and it forces a layer
of escaping onto values purely so they survive being embedded in that
source. Walking the array removes both concerns, and is a good deal
easier to follow.

Two things worth knowing when reading the diff:

- The addcslashes() call on the custom translation value existed only so
  the value would survive being embedded in generated source. With
  nothing embedded, it is removed; keeping it would leave literal
  backslashes in the string the user sees. On PHP 8.1+, where
  htmlspecialchars() defaults to ENT_QUOTES, it already did.

- Values for dotted keys in the language files carry a second level of
  escaping for the same reason. 72 such values exist, in fr, ca, et and
  it. unescapeLangValue() undoes exactly that level on load, so every
  existing translation file keeps working unchanged. Normalising the
  files themselves would remove the need for it, but that is a change to
  translation data and belongs on its own.

get() also stops emitting "Undefined array key" warnings on PHP 8 for
missing keys, which the eval() produced on every lookup of one.
ttValidTranslationLine() decided whether a key was valid by asking
whether it resolved, which ties the validity of input to how a lookup
behaves for input that is not a key at all.

Check the key against the notation it is documented to use -- words
separated by dots -- before any lookup happens.
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