Skip to content

fix(state): escape staterc values so sourcing them is safe - #2198

Open
EnzoItaliano wants to merge 3 commits into
HyDE-Project:devfrom
EnzoItaliano:fix/staterc-quoting
Open

EnzoItaliano wants to merge 3 commits into
HyDE-Project:devfrom
EnzoItaliano:fix/staterc-quoting

Conversation

@EnzoItaliano

@EnzoItaliano EnzoItaliano commented Oct 11, 2026 •

Copy link
Copy Markdown

Pull Request

Description

Values in ~/.local/state/hyde/staterc were written without escaping, but scripts read the file with source (export_hyde_config() in globalcontrol.sh, fastfetch.sh), so bash interpreted what was inside them (#2197):

  • staterc.sh (used by set_conf() and Lua's staterc_set()) wrote KEY="<value>" with the value as-is. theme.switch.sh saves the theme's directory name as HYDE_THEME, so a downloaded theme named Evil$(cd;touch PWNED)`id` ran both commands every time a script loaded staterc. A single " in a value left the quote open, so sourcing failed and no value was set.
  • waybar.py wrote KEY=<value> without quotes, so a layout path with a space made bash run its second word as a command.

This came up in the CodeRabbit review of #2195 (#2195 (comment)); it predates that PR.

Changes:

  • One format for every writer: KEY="<value>" with \, ", $ and the backtick each escaped by a backslash. That is exactly what bash undoes inside double quotes, so source reads back the original value and runs nothing. A value with a newline is refused, since it can't fit on one line.
    • staterc.sh: escapes the value before handing it to awk, and exits 2 for a value with a newline or carriage return.
    • waybar.py: set_state_value() and _add_missing_state_values() write through the new _quote_state_value(), which raises ValueError for a newline.
  • Readers undo the escapes the way source does:
    • Lua staterc_get(): strips the quotes and turns \\, \", \$ and \` back into the character; any other backslash stays.
    • waybar.py get_state_value(): does the same through _unquote_state_value().
    • Lines written by older versions still read correctly: a raw K="back\slash" reads as back\slash, as source reads it, and an unquoted WAYBAR_LAYOUT_PATH=/x/a b.jsonc reads as-is.

Compatibility: a value without any of \ " $ or a backtick is written exactly as before (KEY="value"). hydebar and hyde-button, which read staterc by stripping the surrounding quotes, see no difference. The only visible change is that waybar.py's WAYBAR_* lines now get quotes, which both already handle. weather.py's loader only reads WEATHER_* keys, which don't come from staterc.

Fixes #2197

Related:

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update (non-breaking change; modified files are limited to the documentations)
  • Technical debt (a code change that does not fix a bug or add a feature but makes something clearer for devs)
  • Other (provide details below)

Checklist

Testing

HydeVM (clean install, with the staterc files from dev @ 90bffa6 as the baseline): a copy of Catppuccin Mocha named Evil$(cd;touch PWNED)`id`, applied with theme.switch.sh -s, then staterc sourced in a new shell.

dev @ 90bffa6 this PR
HYDE_THEME line HYDE_THEME="Evil$(cd;touch PWNED)`id`" HYDE_THEME="Evil\$(cd;touch PWNED)\`id\`"
HYDE_THEME after source Eviluid=1000(arch) gid=1000(arch) groups=1000(arch) Evil$(cd;touch PWNED)`id` (exact)
~/PWNED created not created

On the branch, also checked in the same session: switching back to a normal theme, waybar --set, --next ×2 and --prev (the quoted WAYBAR_* lines are read back, the bar stays active), shaders --set, and fastfetch, which sources staterc.

shellcheck and luacheck are clean on the changed files, and pre-commit passes.

Summary by CodeRabbit

  • Bug Fixes
    • State-file values containing quotes, backslashes, dollar signs, or backticks are now escaped consistently, helping preserve their exact contents when saved and read.
    • Lua and Python readers continue to support values written by older versions.
    • Values containing newlines or carriage returns are rejected instead of being written to the state file.

staterc.sh wrote values as-is between double quotes, and staterc is read
with `source`. A theme name with $(...) or a backtick in it ran as a
command, and a single " left the quote open, so sourcing failed and none
of the values were set (HyDE-Project#2197).

Escape \ " $ and the backtick with a backslash, which is what bash undoes
inside double quotes, and refuse a value with a newline. Lua staterc_get()
undoes the same escapes, so it reads back what Lua and set_conf() wrote,
and reads a line from an older HyDE the way `source` does. Values with
none of those characters are written exactly as before.
waybar.py wrote KEY=value with no quotes, so a layout path with a space
made `source` run the second word as a command, and $(...) in a value
ran (HyDE-Project#2197).

Write values the way staterc.sh does: double-quoted, with \ " $ and the
backtick escaped, and refuse a value with a newline. get_state_value()
undoes the escapes, and still reads an unquoted line from an older
waybar.py as it is.
@coderabbitai

coderabbitai Bot commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 279784cb-75dc-4476-87ab-eb9b5494ffe9

📥 Commits

Reviewing files that changed from the base of the PR and between 90bffa6 and c356680.


📒 Files selected for processing (5)
  • CHANGELOG.md
  • Configs/.local/lib/hyde/globalcontrol.sh
  • Configs/.local/lib/hyde/luautils/global/state.lua
  • Configs/.local/lib/hyde/staterc.sh
  • Configs/.local/lib/hyde/waybar.py

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 7 remain after this review.



📝 Walkthrough

Walkthrough

State-file writers now quote and escape backslashes, double quotes, dollar signs, and backticks. They reject newline and carriage-return values. Lua and Python readers decode quoted values and retain support for unquoted values.

Changes

State-file serialization

Layer / File(s) Summary
Write escaped state-file values
CHANGELOG.md, Configs/.local/lib/hyde/globalcontrol.sh, Configs/.local/lib/hyde/staterc.sh, Configs/.local/lib/hyde/waybar.py
Shell and Python writes now use quoted, escaped values. The shell writer reports newline or carriage-return values and exits with status 2; the Python writer raises ValueError. The changelog and set_conf comment describe the serialization behavior.
Decode state-file values
Configs/.local/lib/hyde/luautils/global/state.lua, Configs/.local/lib/hyde/waybar.py
Lua and Python readers unescape supported characters in fully quoted values. Unquoted values remain unchanged.

Priority: ⬆️ High

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: High

Suggested reviewers: krhyme7


Merge Risk: ⚪ Minimal · up to c3566

This change makes values in the state file safe to read with shell source. No concrete merge-blocking risk was identified in the supplied changes.

Pre-merge checks | Passed 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: escaping staterc values so Bash sourcing is safe.
Linked Issues check Passed The PR addresses direct issue #2197. staterc.sh escapes backslashes, double quotes, $, and backticks before writing KEY="...", and rejects newline or carriage-return values. waybar.py uses the…
Out of Scope Changes check Passed The changed files stay within issue #2197. The changelog and comments document the staterc format and the related atomic write behavior. The Lua reader, Python reader, and both writers are necessary f…
Docstring Coverage Passed Docstring coverage is 88.89% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 9 functions across 4 files. (1 skipped: 1 u…

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

A rabbit checks the state-file line,
Then tucks each slash in place.
Quotes and backticks lose their bite,
Old lines keep their familiar face.
No newline hops into the file,
The rabbit bounds away with grace.

Comment @coderabbitai help to get the list of available commands.

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