hermes-agent/plugins
pprism13 9291b786b4 fix(openviking): sanitize embedded newlines when writing .env secrets
`_write_env_vars` in the OpenViking memory provider interpolates each
secret straight into a `KEY=VALUE` line, but the values only ever pass
through `_clean_config_value`, whose `value.strip()` trims surrounding
whitespace and leaves internal CR/LF intact. Because the file is strictly
line-oriented and is re-read via `read_text().splitlines()`, a value that
carries an embedded newline spills onto a second physical line, and the
tail is re-parsed as an independent `KEY=VALUE` entry on the next round
trip. A secret pasted with a trailing record (e.g. an `OPENVIKING_API_KEY`
copied with an extra line) therefore injects an arbitrary additional
variable into the persisted credentials file and silently corrupts it.

The fix neutralizes the line terminators at the single chokepoint where
values reach the file. A small `_env_line_safe` helper strips `\r`, `\n`,
and the NUL byte from each value, and both write sites in `_write_env_vars`
(the existing-key update branch and the appended-key branch) route through
it, so a value can only ever occupy the single line it is written on.

## What does this PR do?

Hardens the OpenViking memory provider's `.env` writer so a malformed or
pasted secret value can no longer break out of its `KEY=VALUE` line and
inject a rogue variable into the profile-scoped credentials file.

## Related Issue

N/A

## Type of Change

- [x] 🐛 Bug fix (non-breaking change that fixes an issue)

## Changes Made

- `plugins/memory/openviking/__init__.py`: add `_env_line_safe()` which
  removes `\r`, `\n`, and `\x00` from a value, and apply it to both the
  updated-key and appended-key write branches in `_write_env_vars()`.
- `tests/plugins/memory/test_openviking_provider.py`: add two regression
  tests covering a fresh write and an in-place key update with embedded
  CR/LF, asserting no injected line survives the read-back.

## How to Test

1. Run the targeted tests:
   `pytest tests/plugins/memory/test_openviking_provider.py -k env_writer -q`
2. Reverting the `_env_line_safe` sanitization makes
   `test_openviking_env_writer_strips_embedded_newlines_in_values` and
   `test_openviking_env_writer_strips_newlines_when_updating_existing_key`
   fail with a rogue `INJECTED_KEY=`/`ROGUE=1` line appearing in the file,
   confirming the tests pin the bug.
3. `ruff check plugins/memory/openviking/__init__.py` and
   `python scripts/check-windows-footguns.py plugins/memory/openviking/__init__.py`
   both pass.

## Checklist

### Code

- [x] I've read the Contributing Guide
- [x] My commit messages follow Conventional Commits
- [x] I searched for existing PRs to make sure this isn't a duplicate
- [x] My PR contains only changes related to this fix
- [x] I've run the relevant tests and they pass
- [x] I've added tests for my changes (required for bug fixes)
- [x] I've tested on my platform: macOS 15 (Darwin 25.5)

### Documentation & Housekeeping

- [x] I've updated relevant documentation (docstrings) — or N/A
- [x] I've updated `cli-config.yaml.example` if I added/changed config keys — N/A
- [x] I've updated `CONTRIBUTING.md` or `AGENTS.md` if I changed architecture or workflows — N/A
- [x] I've considered cross-platform impact (strips CR as well as LF) — done
- [x] I've updated tool descriptions/schemas if I changed tool behavior — N/A

(cherry picked from commit f29dd2df84)
2026-07-24 13:00:53 +05:30
..
browser fix: guard int(os.getenv()) casts against malformed env vars (#40598) 2026-06-07 06:14:24 -07:00
context_engine feat(context-engine): host contract for external context engines 2026-05-28 01:45:30 -07:00
cron_providers fix(cron): harden execution attempt ledger 2026-07-17 04:58:35 -07:00
dashboard_auth feat(dashboard_auth): support confidential clients (client_secret) in self-hosted OIDC (#55344) 2026-06-30 13:32:51 +10:00
disk-cleanup docs(disk-cleanup): clarify cron output-root protection is exact-match 2026-07-01 15:42:04 +05:30
google_meet refactor(setup): route dependency installs through the canonical uv→pip→ensurepip ladder 2026-07-07 04:09:35 -07:00
hermes-achievements fix(achievements): stop card hover click loop 2026-07-16 04:34:57 -07:00
image_gen fix(deepinfra): harden multimodal provider routing 2026-07-14 02:59:39 +05:30
kanban feat(kanban): per-task model dropdown — set/override worker model+provider from the board (#69876) 2026-07-22 22:23:24 -07:00
memory fix(openviking): sanitize embedded newlines when writing .env secrets 2026-07-24 13:00:53 +05:30
model-providers feat(nous): send top-level session_id for provider sticky routing (#69253) 2026-07-22 04:39:20 -07:00
observability fix(nemo-relay): align dynamic plugin configuration 2026-07-13 17:01:08 -06:00
platforms fix(slack): prefer live send adapter and try multi-workspace tokens individually 2026-07-23 12:01:24 -07:00
security-guidance plugins: add security-guidance — pattern-matched warnings on dangerous code writes (#33131) 2026-05-27 02:07:21 -07:00
spotify chore: prune unused imports and duplicate import redefinitions 2026-05-28 22:26:25 -07:00
teams_pipeline fix(teams-pipeline): reject dot-only recording display_name 2026-07-01 02:03:48 -07:00
video_gen fix(video-gen): omit duration for range-based FAL families when unspecified 2026-07-16 04:24:10 -07:00
web fix: sanitize subprocess env for DDGS worker 2026-07-21 11:51:01 +05:30
__init__.py feat(memory): pluggable memory provider interface with profile isolation, review fixes, and honcho CLI restoration (#4623) 2026-04-02 15:33:51 -07:00
plugin_utils.py fix(plugins): thread-safe lazy-singleton helpers; fix honcho TOCTOU (#24759) (#42150) 2026-06-08 09:35:22 -07:00