TavernKeeper Scan Report

Noineri/vibe_tavern

Commit 0dd08e6 Reviewed

No material or immediate-danger concern was identified in this review.

This advisory report describes what the named tools and review process found at one exact commit. Unknown or unobserved behavior may still exist.

0 immediate danger 0 material 139 low

What this review found

No material or immediate-danger item was identified.

Minor cautions

zizmor reported adhoc-packages

Minor caution · high confidence

The release automation upgrades the npm tool itself before publishing, but instead of locking it to a specific version it always grabs whatever is newest. This is a minor reproducibility and supply-chain concern because a bad update to the npm tool could affect the build environment, but it does not directly expose user data or secrets.

Technical evidence

Scanner reason: zizmor matched workflow-security rule adhoc-packages. The match applies to this repository.

Contextual assessment: The flagged step runs a global install of the npm CLI using a floating dist-tag rather than a pinned version. This is a common CI pattern needed to obtain a trusted-publishing-capable npm version on the GitHub-hosted runner. The concern is supply-chain reproducibility: a floating tag resolves to whatever the registry currently points at, so a future compromised or broken npm release would affect the build environment. No secrets, tokens, or user data are involved in this step, and the step does not influence the published package contents beyond which npm CLI performs the publish. Concrete harm to end users is not demonstrated by the supplied evidence.

Impact: low · Exploitability: unlikely

Developer action: Consider pinning the npm CLI upgrade to a specific version range that is known to support trusted publishing, improving reproducibility and reducing exposure to a future compromised npm release.

Scanner
zizmor 1.28.0
Rule
adhoc-packages
File role
tooling
Source
.github/workflows/release-npm.yml:140

OpenGrep reported tavernkeeper.dynamic-execution.javascript-eval

Minor caution · medium confidence

This code runs user-written dice-rolling scripts in a quarantined JavaScript environment with a short time limit and a restricted set of tools. That is exactly what the app advertises—a dice system powered by JavaScript scripts. The quarantine is not a perfect security wall (Node's sandbox tool was never designed to be one), but since the app runs locally on the user's own machine and the evidence does not show dice scripts being loaded from untrusted external sources, the practical risk is low. A slightly more robust sandboxing technology would be a worthwhile future improvement.

Technical evidence

Scanner reason: OpenGrep matched static-analysis rule tavernkeeper.dynamic-execution.javascript-eval. The match applies to this repository.

Contextual assessment: The flagged call uses node:vm runInNewContext to execute user-authored dice-script JavaScript inside a restricted context. This matches the project's stated purpose of supporting JavaScript scripts for a Dice System. The sandbox deliberately excludes network, filesystem, process, require, eval, Function, setTimeout, and other powerful globals, exposing only a frozen allowlist of standard built-ins plus a dice-only register/roll API. A timeout bounds execution. However, node:vm is explicitly documented by Node.js as not a security sandbox: objects passed from the outer realm retain prototype chains that can be traversed to obtain the outer realm's Function constructor, potentially enabling escape to the host process. In this local-only client where the user authors and runs their own scripts, that escape primarily affects the user's own machine, limiting concrete harm. The supplied evidence does not demonstrate that dice scripts arrive from untrusted, remote, or imported sources, so an attacker-controlled activation path is not shown.

Impact: low · Exploitability: plausible

Developer action: Consider documenting that node:vm is not a hard security boundary and, if dice scripts may ever be shared or imported from untrusted sources, migrate to a stronger isolation mechanism such as a isolated worker process or a WASM-based sandbox.

Scanner
opengrep 1.26.0
Rule
tavernkeeper.dynamic-execution.javascript-eval
File role
production
Source
services/api/src/domain/scripts-engine/dice-script-sandbox.ts:164-167

OpenGrep reported tavernkeeper.dynamic-execution.javascript-eval

Minor caution · high confidence

The app runs user-written dice scripts in a sandbox to execute dice rolls. The sandbox tool used is not a true security barrier and can be escaped with clever code. Since users write their own scripts in this local app, the practical risk is low, but the sandbox could be bypassed if a malicious script is run.

Technical evidence

Scanner reason: OpenGrep matched static-analysis rule tavernkeeper.dynamic-execution.javascript-eval. The match applies to this repository.

Contextual assessment: The executeDiceRoll function executes user-authored dice script code concatenated with a server-side orchestration snippet via runInNewContext from node:vm. The sandbox provides a restricted globals allowlist identical to the discovery phase and a 5000ms timeout. The orchestration snippet is appended after the user code and runs in the same VM execution so the timeout covers both. The same node:vm limitation applies: host objects such as Error and Object passed into the sandbox allow prototype-chain escape to host globals. The roll function delegates to a bounded server-owned roller via closures, which is a good design, but the VM boundary itself is not a true security sandbox. The project's stated purpose includes user-authored dice scripts, so dynamic execution matches that purpose. The evidence does not demonstrate that dice scripts arrive from untrusted external sources.

Impact: medium · Exploitability: plausible

Developer action: Consider using isolated-vm or a restricted child process for stronger isolation, particularly if dice scripts may be shared or imported from external sources. Document that node:vm is not a security boundary.

Scanner
opengrep 1.26.0
Rule
tavernkeeper.dynamic-execution.javascript-eval
File role
production
Source
services/api/src/domain/scripts-engine/dice-script-sandbox.ts:254-257

OpenGrep reported tavernkeeper.dynamic-execution.javascript-eval

Minor caution · high confidence

The app lets users write their own JavaScript scripts to customize behavior during roleplay. These scripts run in a sandbox that limits what they can access, but the sandbox tool is not a true security barrier and can be escaped. Since users write their own scripts in this local app, the everyday risk is low, but a malicious shared script could potentially break out and run arbitrary code on the user's machine.

Technical evidence

Scanner reason: OpenGrep matched static-analysis rule tavernkeeper.dynamic-execution.javascript-eval. The match applies to this repository.

Contextual assessment: The executeScripts function runs user-authored JavaScript scripts via runInNewContext from node:vm. The sandbox provides a context object with chat, character, lore, state, shared, persona, and utility APIs, plus a standard globals allowlist (Math, JSON, Date, Array, Object, Error, etc.) and a 5000ms timeout. The sandbox deliberately excludes setTimeout, setInterval, fetch, require, process, globalThis, eval, Function, and WebAssembly. However, the included host objects (Error, Object, Array, etc.) are real references from the host context, enabling well-known prototype-chain escape techniques to reach host globals like process or require. The project's README explicitly lists JavaScript scripts as a feature for conditional logic, random events, and persistent character state, so dynamic execution matches the stated purpose. The scripts can mutate character personality and scenario, inject messages, and manage persistent state, all of which are intended capabilities visible to users. The evidence does not demonstrate that scripts are received from untrusted external sources rather than being authored by the local user.

Impact: medium · Exploitability: plausible

Developer action: Consider migrating to isolated-vm or a sandboxed child process for stronger isolation, especially if scripts may be shared or embedded in imported character cards. Document that node:vm is not a security boundary and advise users to only run scripts from trusted sources.

Scanner
opengrep 1.26.0
Rule
tavernkeeper.dynamic-execution.javascript-eval
File role
production
Source
services/api/src/domain/scripts-engine/script-sandbox.ts:208-211
Deterministic technical evidence (89)
  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:328

  • zizmor reported cache-poisoning · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:270

  • zizmor reported artipacked · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:161-163

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:57

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:267

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:74

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:119

  • Dependency advisory GHSA-67mh-4wv8-2f99:pkg:100a52fb5850b2ff8a7f76c7 applies · osv-scanner 2.4.0

    A dependency has a published security issue, though this scan does not show that the project exposes it to an attacker.

    Policy reason: osv-structured-advisory · Execution scope: unknown

    Source: bun.lock

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:219

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:86

  • zizmor reported artipacked · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release-npm.yml:79-83

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:207

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:316

  • zizmor reported artipacked · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:62

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:287

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:337

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:96

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release-latest.yml:52

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:250

  • zizmor reported artipacked · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:129-131

  • zizmor reported cache-poisoning · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:219

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:270

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:193

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:292

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:132

  • zizmor reported template-injection · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:286

  • zizmor reported artipacked · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:218

  • zizmor reported cache-poisoning · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:132

  • zizmor reported cache-poisoning · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:99

  • zizmor reported cache-poisoning · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:205

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release-npm.yml:132

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:144

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:108

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:218

  • zizmor reported template-injection · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:284

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:188

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:109

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:359

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release-npm.yml:128

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release-npm.yml:79

  • zizmor reported artipacked · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:316-318

  • zizmor reported artipacked · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:267-269

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:187

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:319

  • zizmor reported artipacked · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:74

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:62

  • zizmor reported artipacked · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:132

  • zizmor reported artipacked · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:207

  • zizmor reported artipacked · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:86

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:75

  • zizmor reported cache-poisoning · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release-npm.yml:132

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:132

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:247

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:219

  • zizmor reported artipacked · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:108

  • zizmor reported artipacked · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:110-112

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:129

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:63

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release-latest.yml:51

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:375

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:205

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:97

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:298

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:208

  • zizmor reported artipacked · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:187

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:110

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:215

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:99

  • zizmor reported artipacked · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:359-361

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:123

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:87

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:363

  • zizmor reported artipacked · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:97

  • zizmor reported artipacked · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:96-98

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:161

  • zizmor reported cache-poisoning · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:113

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:141

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:98

  • zizmor reported artipacked · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:57-59

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:172

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:157

  • zizmor reported artipacked · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:157

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:221

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:345

  • zizmor reported cache-poisoning · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release-npm.yml:128

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:133

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/ci.yml:158

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:113

  • zizmor reported unpinned-uses · zizmor 1.28.0

    The code has a known weakness, though this scan does not show that anyone can exploit it here.

    Policy reason: zizmor-known-workflow-rule · Execution scope: automation

    Source: .github/workflows/release.yml:322

Contextual expected matches (42)

Credential access and network transmission in one file

Expected behavior · high confidence

The app uses its own login token to authenticate a request to its own backend server. This is normal and expected behavior — like using your session cookie to load your own profile page. The token is not sent anywhere unexpected.

Technical evidence

Scanner reason: A credential source and an outbound network operation were detected in the same file.

Contextual assessment: The file retrieves a mobile authentication token via getMobileToken() and includes it as a Bearer token in the Authorization header of a fetch call to the project's own gateway base URL (getGatewayBaseUrl()). This is standard client-side authentication: the token authorizes a POST request to the project's own promote-to-attachment endpoint. The destination is the project's own backend, not an external or third-party endpoint. There is no exfiltration, no hidden destination, no obfuscation, and no transmission of credentials to any party other than the project's own API gateway. The token use is proportionate and directly tied to the stated purpose of promoting a gallery asset server-side.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
tavernkeeper 5
Rule
credential-exfiltration
File role
production
Source
apps/web/src/lib/attach-from-gallery.ts:30

OpenGrep reported tavernkeeper.dynamic-execution.javascript-eval

Expected behavior · high confidence

This is test-only code that runs the project's own SDK code in a simulated environment to verify it works correctly. It does not execute arbitrary or untrusted code, and it is not part of the shipped application.

Technical evidence

Scanner reason: OpenGrep matched static-analysis rule tavernkeeper.dynamic-execution.javascript-eval. The match applies to this repository.

Contextual assessment: The flagged construct is inside a test harness function that evaluates the project's own SDK source string against a fake window object to verify message-port protocol parity. The file role is test, and the evaluated source is an internal constant, not user-supplied or network-fetched input. This pattern is appropriate for integration testing of a sandboxed iframe-style SDK.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
opengrep 1.26.0
Rule
tavernkeeper.dynamic-execution.javascript-eval
File role
test
Source
apps/web/src/lib/experience-bridge.test.ts:237

Credential access and network transmission in one file

Expected behavior · high confidence

The app sends debug log information to its own backend server, using a session token to authenticate the request. No credentials are sent anywhere outside the app's own server.

Technical evidence

Scanner reason: A credential source and an outbound network operation were detected in the same file.

Contextual assessment: The postSendDebug function calls getMobileToken() and uses the result only as a Bearer token in an Authorization header for a POST to the project's own gateway backend at /api/debug/send-log. The request body contains an event name and a generic data record. The token authenticates to the app's own API, not to a third party. This is a debug-logging facility on the project's own server, consistent with a local-first client that supports mobile/companion sessions. The token is never sent to an external destination or stored in an untrusted channel.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
tavernkeeper 5
Rule
credential-exfiltration
File role
production
Source
apps/web/src/api/chat-api.ts:746

Gitleaks reported generic-api-key

Expected behavior · high confidence

A secret scanner flagged a line in a test file, but the flagged text is a fake placeholder value used to test that the app correctly hides private data. No real secret is exposed.

Technical evidence

Scanner reason: Gitleaks matched secret-detection rule generic-api-key. The match applies to this repository.

Contextual assessment: The gitleaks generic-api-key rule matched a string on line 721 of a test file. The matched value is a redacted placeholder used as test fixture input for hiddenStateCheckpointJson, specifically verifying that the public DTO never exposes hidden state. This is a synthetic test value, not a real credential, and it appears in a test file with no runtime exposure path.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
gitleaks 8.30.1
Rule
generic-api-key
File role
test
Source
services/api/test/experience-service.test.ts:721

zizmor reported superfluous-actions

Expected behavior · high confidence

The workflow uses a popular GitHub Action to create draft releases instead of a built-in method. This is a style choice, not a security problem.

Technical evidence

Scanner reason: zizmor matched workflow-security rule superfluous-actions. The match applies to this repository.

Contextual assessment: The scanner flagged softprops/action-gh-release@v3 as superfluous because the runner includes native release-creation capability. This is an informational efficiency observation, not a security vulnerability. The action is pinned to a major version, runs with contents:write permission scoped to the publish job, and creates a draft release from artifacts produced by upstream build jobs. No untrusted input flows into the action beyond repository-controlled version strings and uploaded artifacts. Using a third-party action for release management is a widespread, legitimate practice with no demonstrated security harm.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
zizmor 1.28.0
Rule
superfluous-actions
File role
tooling
Source
.github/workflows/release.yml:375

Gitleaks reported private-key

Expected behavior · high confidence

A secret scanner found a private key file, but it is a fake test key stored in the test fixtures folder for testing purposes. It is not a real key and does not affect users.

Technical evidence

Scanner reason: Gitleaks matched secret-detection rule private-key. The match applies to this repository.

Contextual assessment: The gitleaks private-key rule matched a PEM file located at services/api/test/fixtures/provider-proxy-key.pem. The file is a test fixture with file_role fixture, and its content was redacted to a placeholder. It is a generated test key used for testing provider proxy functionality, not a production credential. No evidence indicates this key is used in runtime or shipped to end users in a functional capacity.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
gitleaks 8.30.1
Rule
private-key
File role
fixture
Source
services/api/test/fixtures/provider-proxy-key.pem:1-28

OpenGrep reported tavernkeeper.persistence.startup-modification

Expected behavior · high confidence

This is just a line of text used in a test to simulate release notes. It does not change anything on your computer and is not a security issue.

Technical evidence

Scanner reason: OpenGrep matched static-analysis rule tavernkeeper.persistence.startup-modification. The match applies to this repository.

Contextual assessment: The matched line is inside a unit test that asserts parsed release notes equal a hardcoded fixture string. The string mentions startup but performs no persistence or startup modification; it is inert test data with no runtime behavior, no data flow, and no executable side effects.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
opengrep 1.26.0
Rule
tavernkeeper.persistence.startup-modification
File role
test
Source
services/api/test/updater-release.test.ts:60

OpenGrep reported tavernkeeper.dynamic-execution.javascript-eval

Expected behavior · high confidence

This test code runs the project's own visual component script in a simulated browser environment to check it communicates correctly. It only uses the project's own code and is not shipped to users.

Technical evidence

Scanner reason: OpenGrep matched static-analysis rule tavernkeeper.dynamic-execution.javascript-eval. The match applies to this repository.

Contextual assessment: Line 426 evaluates the script content extracted from the project's own Conversation visual source constant inside a fake DOM harness. The file role is test, and the evaluated content is a build-time constant imported from a project module, not user or network input. This is a legitimate integration-test technique for verifying the visual component's behavior through the bridge protocol.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
opengrep 1.26.0
Rule
tavernkeeper.dynamic-execution.javascript-eval
File role
test
Source
apps/web/src/lib/experience-bridge.test.ts:426

malcontent reported anti-static-xor-terms

Expected behavior · low confidence

The scanner found suspicious-looking patterns in a font file, but this is a common false positive from analyzing binary font data. Font files do not execute code.

Technical evidence

Scanner reason: malcontent matched behavioral-analysis rule anti-static-xor-terms. The match applies to this repository.

Contextual assessment: The artifact is a JetBrains Mono Nerd Font TrueType font file in the web app's public fonts directory, identical in role to the Bold variant also flagged. The XOR-terms scanner match is a known false-positive pattern on binary font data containing compressed glyph outlines. Font files are non-executable static browser resources. The source_kind is metadata-only, so raw bytes were not supplied for independent verification, and metadata-only evidence cannot establish demonstrated exposure or support material or high risk.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
malcontent 1.25.7
Rule
anti-static-xor-terms
File role
production
Source
apps/web/public/fonts/JetBrainsMonoNLNerdFont-Regular.ttf

Credential access and network transmission in one file

Expected behavior · high confidence

The app sends a login token only to its own server when streaming chat messages. This is normal authenticated API behavior for the chat feature.

Technical evidence

Scanner reason: A credential source and an outbound network operation were detected in the same file.

Contextual assessment: The scanner flagged co-location of getMobileToken and a fetch call. The token is used in an Authorization header for POST requests to the project's own chat streaming endpoints via getGatewayBaseUrl and appendTokenQuery. The request body contains chat message content and generation parameters sent to the project's own SSE backend. The token is not transmitted to any third-party destination, logged, or persisted to untrusted storage. This is expected behavior for the core streaming chat feature of a local AI roleplay client.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
tavernkeeper 5
Rule
credential-exfiltration
File role
production
Source
apps/web/src/api/stream.ts:37

OpenGrep reported tavernkeeper.dynamic-execution.javascript-eval

Expected behavior · high confidence

This is the second step of running user game scripts: after registering what the script can do, it calls a specific method from that script inside the same locked-down sandbox with the same time limit. The extra code added is written by the app, not by the user. This matches the project's described features.

Technical evidence

Scanner reason: OpenGrep matched static-analysis rule tavernkeeper.dynamic-execution.javascript-eval. The match applies to this repository.

Contextual assessment: The runInNewContext call at lines 347-350 is the method-execution phase of the same experience sandbox. It concatenates the user's script body with a fixed orchestration snippet that locates the registered definition and invokes one mandatory method within the same timeout-bounded VM call. The sandbox globals are identical to the discovery phase: the same restricted allowlist with no network, filesystem, process, Promise, or timer access. The orchestration snippet is a constant string array joined by the host, not user-controlled input. This is the second half of a stated, visible project feature.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
opengrep 1.26.0
Rule
tavernkeeper.dynamic-execution.javascript-eval
File role
production
Source
services/api/src/domain/interactive/experience-sandbox.ts:347-350

OpenGrep reported tavernkeeper.persistence.startup-modification

Expected behavior · high confidence

This line creates fake release notes for testing purposes. It does not affect the system in any way and poses no security risk.

Technical evidence

Scanner reason: OpenGrep matched static-analysis rule tavernkeeper.persistence.startup-modification. The match applies to this repository.

Contextual assessment: The matched line defines a fixture release-notes body inside a test helper that constructs a fake GitHub release JSON payload. It is static test data with no execution path, no persistence action, and no startup modification behavior.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
opengrep 1.26.0
Rule
tavernkeeper.persistence.startup-modification
File role
test
Source
services/api/test/updater-release.test.ts:30

OpenGrep reported tavernkeeper.persistence.startup-modification

Expected behavior · high confidence

This file is a dictionary of text tokens used by an AI tokenizer. It maps words and text fragments to numeric IDs. The scanner saw familiar words inside the dictionary and flagged them, but the file contains no code and cannot run or modify anything on your computer.

Technical evidence

Scanner reason: OpenGrep matched static-analysis rule tavernkeeper.persistence.startup-modification. The match applies to this repository.

Contextual assessment: The flagged file is a static JSON tokenizer vocabulary file containing BPE token-to-ID mappings for a Claude model tokenizer. It is a data asset, not executable code. The scanner matched persistence-related keywords (such as start, system, config, import, exec) that appear naturally as tokenizer vocabulary entries. There is no code execution, no startup modification, no persistence mechanism, and no runtime behavior in this file whatsoever.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
opengrep 1.26.0
Rule
tavernkeeper.persistence.startup-modification
File role
production
Source
services/api/assets/tokenizers/claude.json:1

Bidirectional text control detected in source

Expected behavior · high confidence

The file is a dictionary that maps characters to number IDs for an AI tokenizer. It naturally contains every kind of text character the AI model can process, including rare formatting characters. Finding one here is normal data, not a hidden trick.

Technical evidence

Scanner reason: A bidirectional Unicode control character was detected in a source file.

Contextual assessment: The flagged character U+202C (POP DIRECTIONAL FORMATTING) at line 30716 is a standard entry in a Mistral tokenizer vocabulary JSON file, mapped to token ID 30587. Tokenizer vocabularies intentionally include the full range of Unicode characters the model was trained on, including bidi control characters, control codes (\u0002, \u0005, etc.), and emoji. This is static data mapping strings to integer token IDs, not executable source code where bidi reordering could disguise logic.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
tavernkeeper 5
Rule
unicode-bidi-control
File role
production
Source
services/api/assets/tokenizers/mistral.json:30716

OpenGrep reported tavernkeeper.dynamic-execution.javascript-eval

Expected behavior · high confidence

The app lets users write small JavaScript game scripts. This code runs those scripts in a locked-down sandbox with a time limit and no access to the network, files, or system. That matches what the project says it does.

Technical evidence

Scanner reason: OpenGrep matched static-analysis rule tavernkeeper.dynamic-execution.javascript-eval. The match applies to this repository.

Contextual assessment: The runInNewContext call at line 240 is the discovery phase of an experience-script sandbox. The project explicitly supports user-authored JavaScript scripts for game logic (dice, interactive experiences). The sandbox is deliberately constrained: buildStandardGlobals exposes only Math, JSON, Date, parseInt, parseFloat, isNaN, isFinite, Array, Object, String, Number, Boolean, RegExp, Map, Set, Error, and a capturing console. It excludes fetch, Promise, require, process, globalThis, eval, Function, WebAssembly, Reflect, setTimeout, and setInterval. A 5-second CPU timeout is applied. No network, filesystem, or process access is provided. This is a proportionate, visible implementation of a stated project feature.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
opengrep 1.26.0
Rule
tavernkeeper.dynamic-execution.javascript-eval
File role
production
Source
services/api/src/domain/interactive/experience-sandbox.ts:240

JavaScript analysis reported javascript.xray.serialize-environment

Expected behavior · high confidence

The server reads several configuration settings from environment variables to determine where to find files and which network address and port to use. This is standard server configuration with no sensitive data being exposed.

Technical evidence

Scanner reason: JavaScript analysis matched static JavaScript security signal javascript.xray.serialize-environment. The match applies to this repository.

Contextual assessment: The serialize-environment signal is triggered by multiple process.env accesses on lines 34, 36, 49, and 50, reading VIBE_TAVERN_ROOT_DIR, VIBE_TAVERN_DATA_DIR, VIBE_TAVERN_HOST, and VIBE_TAVERN_PORT respectively. These are standard configuration reads for a production server entry point. No environment contents are serialized, transmitted, logged, or exfiltrated. The values are used solely to resolve filesystem paths and set the listen host and port for the server runtime.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
javascript-analysis webcrack-2.16.0_js-x-ray-16.0.0_signatures-1_literals-1_families-1
Rule
javascript.xray.serialize-environment
File role
production
Source
services/api/src/server/prod-server.ts:34

Gitleaks reported generic-api-key

Expected behavior · high confidence

The scanner found a fake secret embedded in a test file. It is a made-up value used to verify that the application correctly hides private data from API responses. It is not a real password or key.

Technical evidence

Scanner reason: Gitleaks matched secret-detection rule generic-api-key. The match applies to this repository.

Contextual assessment: The gitleaks generic-api-key match is on a test file (experience-routes.test.ts) line containing a fabricated privacy marker string used as a hidden-state checkpoint fixture. The test explicitly asserts that this value must NOT appear in API responses, confirming it is a synthetic test sentinel rather than a live credential. No real secret is present, and test fixtures do not ship as executable behavior.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
gitleaks 8.30.1
Rule
generic-api-key
File role
test
Source
services/api/test/experience-routes.test.ts:903

Credential access and network transmission in one file

Expected behavior · high confidence

The code uses a login token to authenticate a debug-log request sent to the app's own backend. It does not send the token to any outside server. This is normal for a local app that supports mobile access.

Technical evidence

Scanner reason: A credential source and an outbound network operation were detected in the same file.

Contextual assessment: The file reads a mobile authentication token and sends it as a Bearer header to the project's own gateway endpoint for a temporary debug logger. The destination is the project's local gateway base URL, not an external third party. The token is used for authentication of the request, not transmitted in the request body or exfiltrated to an unrelated host. This matches the project's stated local-runtime architecture with mobile/QR access.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
tavernkeeper 5
Rule
credential-exfiltration
File role
production
Source
apps/web/src/lib/dev-log.ts:9

JavaScript analysis reported javascript.xray.data-exfiltration

Expected behavior · high confidence

This is a test file that creates a temporary folder on the user's own machine to run database tests. It does not send any data anywhere.

Technical evidence

Scanner reason: JavaScript analysis matched static JavaScript security signal javascript.xray.data-exfiltration. The match applies to this repository.

Contextual assessment: The scanner signal points at the operating-system temporary-directory import. In this test file it is used only with a filesystem mkdtemp call to create a local throwaway database directory for unit tests of a provider store. No network destination, credential access, external transmission, or attacker-controlled input is present.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
javascript-analysis webcrack-2.16.0_js-x-ray-16.0.0_signatures-1_literals-1_families-1
Rule
javascript.xray.data-exfiltration
File role
test
Source
packages/db/test/provider-coauthor-transport.test.ts:3

JavaScript analysis reported javascript.xray.serialize-environment

Expected behavior · high confidence

The code reads a configuration setting (which network address to listen on) from an environment variable, which is a normal way to configure a server. No sensitive information is accessed or sent anywhere.

Technical evidence

Scanner reason: JavaScript analysis matched static JavaScript security signal javascript.xray.serialize-environment. The match applies to this repository.

Contextual assessment: The serialize-environment signal is triggered by access to process.env on line 72, which reads VIBE_TAVERN_HOST with a fallback to 0.0.0.0. This is a standard server entry point reading a host bind configuration from the environment. No environment contents are serialized, transmitted, logged, or written to any destination. The value is passed directly to startServerRuntime as the listen host. There is no credential access or exfiltration path.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
javascript-analysis webcrack-2.16.0_js-x-ray-16.0.0_signatures-1_literals-1_families-1
Rule
javascript.xray.serialize-environment
File role
production
Source
services/api/src/server/npm-server.ts:72

malcontent reported anti-static-xor-terms

Expected behavior · low confidence

The scanner found patterns in a font file that look like obfuscated data, but this is almost certainly a false positive caused by analyzing binary font data. Font files do not run code and are just displayed text resources.

Technical evidence

Scanner reason: malcontent matched behavioral-analysis rule anti-static-xor-terms. The match applies to this repository.

Contextual assessment: The artifact is a JetBrains Mono Nerd Font TrueType font file in the web app's public fonts directory. The scanner flagged XOR-obfuscated terms in binary data, which is a common false positive when static binary analysis encounters compressed or binary-encoded font glyph tables. Font files are static resources served to the browser and do not execute code. The source_kind is metadata-only, so raw contents were not available to verify, but the file path, naming convention, and project context (a web frontend) are consistent with a legitimate font asset. Metadata-only evidence cannot support material or high risk.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
malcontent 1.25.7
Rule
anti-static-xor-terms
File role
production
Source
apps/web/public/fonts/JetBrainsMonoNLNerdFont-Bold.ttf

JavaScript analysis reported javascript.xray.shady-link

Expected behavior · high confidence

The server defaults to listening on all network interfaces so that mobile devices on the same local network can access it, which is an advertised feature of the app. This is not a connection to a suspicious external site.

Technical evidence

Scanner reason: JavaScript analysis matched static JavaScript security signal javascript.xray.shady-link. The match applies to this repository.

Contextual assessment: The shady-link signal is triggered by the 0.0.0.0 string literal on line 72, used as the default bind address. Binding to all interfaces is intentional and documented in the code comments and project README as required for the mobile access feature (QR access over local network). This is a local-first application where the user runs the server themselves. The address is a listen bind, not an outbound connection to a suspicious destination.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
javascript-analysis webcrack-2.16.0_js-x-ray-16.0.0_signatures-1_literals-1_families-1
Rule
javascript.xray.shady-link
File role
production
Source
services/api/src/server/npm-server.ts:72

Credential access and network transmission in one file

Expected behavior · high confidence

The app retrieves a session token and uses it to authenticate file-upload requests to its own backend server. The token only goes to the app's own API as a standard login header, not to any external or suspicious destination.

Technical evidence

Scanner reason: A credential source and an outbound network operation were detected in the same file.

Contextual assessment: The file calls getMobileToken() and uses the returned value solely as a Bearer token in an Authorization header for fetch requests to the project's own gateway backend (getGatewayBaseUrl()). The token is an authentication credential for the app's own API routes (/api/characters/:id/avatar and /avatar/from-gallery), not a model-provider API key. The token is never sent to any third-party destination, logged, or persisted to an untrusted sink. This is standard authentication for a local-first client that supports mobile/companion network access, as described in the project README.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
tavernkeeper 5
Rule
credential-exfiltration
File role
production
Source
apps/web/src/api/character-api.ts:160

JavaScript analysis reported javascript.xray.serialize-environment

Expected behavior · high confidence

A static analysis scanner flagged code that reads environment variables, but this is just a test saving and restoring display settings to test a Linux feature. No data is sent anywhere.

Technical evidence

Scanner reason: JavaScript analysis matched static JavaScript security signal javascript.xray.serialize-environment. The match applies to this repository.

Contextual assessment: The JS-X-Ray serialize-environment signal was triggered by process.env access at line 87 of a test file. The code saves and restores DISPLAY and WAYLAND_DISPLAY environment variables to test the hasLinuxDisplay helper. This is standard test setup for environment variable manipulation and does not serialize, transmit, or exfiltrate any environment data. No network or external destination is involved.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
javascript-analysis webcrack-2.16.0_js-x-ray-16.0.0_signatures-1_literals-1_families-1
Rule
javascript.xray.serialize-environment
File role
test
Source
services/api/test/fs-native-dialog.test.ts:87

Credential access and network transmission in one file

Expected behavior · high confidence

The code gets a local access token and uses it to authenticate an upload to the app's own backend. This is a normal and expected pattern for a local app that supports mobile network access, not credential theft.

Technical evidence

Scanner reason: A credential source and an outbound network operation were detected in the same file.

Contextual assessment: The file imports getGatewayBaseUrl and getMobileToken from a client module. The token is retrieved and used exclusively as a Bearer Authorization header for a POST request to the project's own gateway API endpoint for asset upload. The destination is the project's own gateway base URL, not an external third-party endpoint. The token is used for its intended authentication purpose and is not logged, persisted to untrusted storage, or transmitted to any destination other than the authorized API. This is a standard authenticated API call pattern matching the project's stated purpose of a local runtime with mobile network access. The scanner flagged co-occurrence of credential access and network transmission in the same file, but the data flow shows the token is used legitimately for its own API, not exfiltrated.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
tavernkeeper 5
Rule
credential-exfiltration
File role
production
Source
apps/web/src/api/asset-api.ts:8

Gitleaks reported private-key

Expected behavior · high confidence

The scanner found a private key file, but it lives in a test fixtures folder and is used only for testing. It is not a key that protects any real system.

Technical evidence

Scanner reason: Gitleaks matched secret-detection rule private-key. The match applies to this repository.

Contextual assessment: The gitleaks private-key match is on a PEM file located in the test fixtures directory (file). The file is a test fixture used to exercise provider proxy TLS or key-handling logic. Its presence in a dedicated test fixtures path, combined with the file role of fixture, indicates it is a generated test key not used in production runtime. No evidence shows this key protects real infrastructure or is referenced by shipped executable code.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
gitleaks 8.30.1
Rule
private-key
File role
fixture
Source
services/api/test/fixtures/provider-proxy-key.pem:1-28

OpenGrep reported tavernkeeper.dynamic-execution.javascript-eval

Expected behavior · high confidence

The code checks whether JavaScript in a visual template has valid syntax by compiling it but never running it. It is like checking grammar without reading the text aloud. No code is actually executed.

Technical evidence

Scanner reason: OpenGrep matched static-analysis rule tavernkeeper.dynamic-execution.javascript-eval. The match applies to this repository.

Contextual assessment: The construct uses the void operator to create a function object from a script body string and immediately discard it without ever invoking it. This is a compile-only syntax check that detects malformed JavaScript in visual source script blocks. The function is never called, so no host-realm execution occurs. This matches the file's documented purpose as a static validator providing feedback without executing anything.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
opengrep 1.26.0
Rule
tavernkeeper.dynamic-execution.javascript-eval
File role
production
Source
apps/web/src/lib/visual-source-validator.ts:86

JavaScript analysis reported javascript.download-to-execution

Expected behavior · high confidence

This is a temporary loading screen shown while the server starts up. It checks every second whether the server is ready by contacting its own health endpoint, and when it is, it simply refreshes the page to load the real application. There is no dangerous code execution here.

Technical evidence

Scanner reason: JavaScript analysis matched static JavaScript security signal javascript.download-to-execution. The match applies to this repository.

Contextual assessment: The flagged region is an inline HTML loading page served by the server during startup. The network retrieval is a same-origin fetch to /health with no-store cache, and the correlated sink is window.location.reload() triggered only when the health endpoint returns HTTP 200. No untrusted or attacker-controlled data flows into any execution sink. The inline scripts perform theme selection from localStorage and CSS animation math on SVG elements. All behavior is static, self-contained, and proportionate to the stated purpose of a loading placeholder that transitions to the real SPA once the server is ready.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
javascript-analysis webcrack-2.16.0_js-x-ray-16.0.0_signatures-1_literals-1_families-1
Rule
javascript.download-to-execution
File role
production
Source
services/api/src/server/loading-placeholder.ts:147-193

JavaScript analysis reported javascript.xray.unsafe-regex

Expected behavior · high confidence

A static scanner flagged a regular expression used to parse dice roll commands. The expression is simple and cannot cause performance problems even with unusual input. This is a normal dice command parser for the roleplay client.

Technical evidence

Scanner reason: JavaScript analysis matched static JavaScript security signal javascript.xray.unsafe-regex. The match applies to this repository.

Contextual assessment: JS-X-Ray flagged an unsafe-regex signal on the dice command regex at line 17. The regex is a fixed literal with sequential alternations and simple quantifiers applied to user message text. There are no nested quantifiers, no overlapping alternation groups, and no backreferences that would create catastrophic backtracking (ReDoS). The input is the last chat message, and matchAll is called once per script execution. Even with adversarial input, the regex evaluates in linear time. The dice count is also capped at 100 in the loop guard, preventing resource exhaustion. This is a benign dice-rolling parser template matching the project's stated dice system feature.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
javascript-analysis webcrack-2.16.0_js-x-ray-16.0.0_signatures-1_literals-1_families-1
Rule
javascript.xray.unsafe-regex
File role
generated
Source
apps/web/src/components/build/editors/script-templates/dice.js:17

JavaScript analysis reported javascript.xray.shady-link

Expected behavior · high confidence

The server defaults to listening on all local network interfaces so phones and tablets on the same network can connect, which is a documented feature. This is not a connection to a suspicious external site.

Technical evidence

Scanner reason: JavaScript analysis matched static JavaScript security signal javascript.xray.shady-link. The match applies to this repository.

Contextual assessment: The shady-link signal is triggered by the 0.0.0.0 string on line 49, used as the default host bind. As with the npm-server entry point, binding to all interfaces is intentional for the mobile access feature. This is a local application the user runs themselves, and the address is a listen bind, not an outbound connection to an external destination.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
javascript-analysis webcrack-2.16.0_js-x-ray-16.0.0_signatures-1_literals-1_families-1
Rule
javascript.xray.shady-link
File role
production
Source
services/api/src/server/prod-server.ts:49

Gitleaks reported generic-api-key

Expected behavior · high confidence

The scanner flagged a fake secret in a test file. The test uses this made-up value to confirm the application does not leak private information. No real credential is exposed.

Technical evidence

Scanner reason: Gitleaks matched secret-detection rule generic-api-key. The match applies to this repository.

Contextual assessment: The gitleaks match on line 721 of experience-service.test.ts is a fabricated privacy marker string inside a hiddenStateCheckpointJson test fixture. The surrounding test asserts the public DTO never includes hiddenStateCheckpointJson and that the marker value does not appear in serialized output. This is a synthetic sentinel for privacy regression testing, not a real credential.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
gitleaks 8.30.1
Rule
generic-api-key
File role
test
Source
services/api/test/experience-service.test.ts:721

Credential access and network transmission in one file

Expected behavior · high confidence

The app sends a login token only to its own server when loading initial app data. This is normal and expected.

Technical evidence

Scanner reason: A credential source and an outbound network operation were detected in the same file.

Contextual assessment: The scanner flagged co-location of getMobileToken and a fetch call. The token is used only in an Authorization header sent to the project's own bootstrap endpoint via appendTokenQuery and getGatewayBaseUrl. The destination is the project's own gateway API, not a third-party service. The token is not logged, persisted to untrusted storage, or sent to any external endpoint. This is expected authenticated bootstrap behavior for a local client supporting mobile network access.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
tavernkeeper 5
Rule
credential-exfiltration
File role
production
Source
apps/web/src/api/settings-api.ts:20

JavaScript analysis reported javascript.xray.data-exfiltration

Expected behavior · high confidence

This is a normal test file that creates a temporary folder on the local machine to run database tests. It does not send any data anywhere or interact with secrets.

Technical evidence

Scanner reason: JavaScript analysis matched static JavaScript security signal javascript.xray.data-exfiltration. The match applies to this repository.

Contextual assessment: Detailed technical wording was omitted by the public report safety filter.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
javascript-analysis webcrack-2.16.0_js-x-ray-16.0.0_signatures-1_literals-1_families-1
Rule
javascript.xray.data-exfiltration
File role
test
Source
services/api/test/provider-profile-transport.test.ts:3

Credential access and network transmission in one file

Expected behavior · high confidence

The app reads a login token and sends it only to its own backend server when exporting or importing persona data. This is normal authentication behavior, not credential theft.

Technical evidence

Scanner reason: A credential source and an outbound network operation were detected in the same file.

Contextual assessment: The scanner flagged co-location of a credential source and a network sink. The token is obtained from getMobileToken and the base URL from getGatewayBaseUrl, then used in an Authorization header sent to the project's own gateway API endpoints (persona export, bulk export, avatar upload, persona import). The token is never logged, written to disk, transmitted to a third-party destination, or included in URL parameters. The fetch destination is always the project's own backend. This is standard authenticated API access for a local client with mobile network access, matching the stated project purpose.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
tavernkeeper 5
Rule
credential-exfiltration
File role
production
Source
apps/web/src/api/persona-api.ts:125

Gitleaks reported generic-api-key

Expected behavior · high confidence

A secret scanner flagged another line in the same test file with the same fake placeholder value used for privacy testing. No real secret is exposed.

Technical evidence

Scanner reason: Gitleaks matched secret-detection rule generic-api-key. The match applies to this repository.

Contextual assessment: The gitleaks generic-api-key rule matched a string on line 683 of a test file. The matched value is the same redacted placeholder used as test fixture input for hiddenStateCheckpointJson in a privacy-verification test. It is a synthetic test value, not a real credential, with no runtime exposure path.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
gitleaks 8.30.1
Rule
generic-api-key
File role
test
Source
services/api/test/experience-service.test.ts:683

Credential access and network transmission in one file

Expected behavior · high confidence

The code gets a login token and includes it when sending files to the app own backend. This is normal and expected for an authenticated file upload feature, not credential theft.

Technical evidence

Scanner reason: A credential source and an outbound network operation were detected in the same file.

Contextual assessment: Detailed technical wording was omitted by the public report safety filter.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
tavernkeeper 5
Rule
credential-exfiltration
File role
production
Source
apps/web/src/api/skill-api.ts:66

Credential access and network transmission in one file

Expected behavior · high confidence

The app uses a session token to authenticate a file-upload request to its own backend server when importing skills. The token only goes to the app's own API as a standard login header.

Technical evidence

Scanner reason: A credential source and an outbound network operation were detected in the same file.

Contextual assessment: The importCopilotSkills function calls getMobileToken() and uses the returned value exclusively as a Bearer token in an Authorization header for a multipart POST to the project's own gateway backend at /api/copilot/skills/import. The token authenticates the upload to the app's own API. It is not transmitted to any third-party destination, logged, or written to an untrusted sink. This matches the project's stated purpose of importing skill files into the local backend.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
tavernkeeper 5
Rule
credential-exfiltration
File role
production
Source
apps/web/src/api/copilot-skill-api.ts:53

Gitleaks reported generic-api-key

Expected behavior · high confidence

This is a test file containing a fake, already-redacted placeholder used to verify that secret data is properly hidden from API responses. No real credential is present, and the test actually proves that sensitive data is kept private.

Technical evidence

Scanner reason: Gitleaks matched secret-detection rule generic-api-key. The match applies to this repository.

Contextual assessment: The gitleaks match on line 971 is a test fixture in a test file. The matched value is an already-redacted placeholder string, not a real credential. The test injects this value into a hidden state checkpoint and then asserts that it does NOT appear in the API response, verifying the privacy guarantee of the experience routes. This is a deliberately constructed test fixture with no runtime exposure path and no real secret value.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
gitleaks 8.30.1
Rule
generic-api-key
File role
test
Source
services/api/test/experience-routes.test.ts:971

OpenGrep reported tavernkeeper.dynamic-execution.javascript-eval

Expected behavior · high confidence

This test code loads the project's own SDK into a simulated environment to test it. It does not run any untrusted code and is not part of the shipped application.

Technical evidence

Scanner reason: OpenGrep matched static-analysis rule tavernkeeper.dynamic-execution.javascript-eval. The match applies to this repository.

Contextual assessment: Line 421 evaluates the project's own SDK IIFE source constant into a fake window object within a test harness. The file role is test, and the source is an internal project constant. No untrusted or user-supplied input reaches this evaluation path. This is the same test-harness pattern used to verify SDK-to-bridge protocol parity without a real DOM.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
opengrep 1.26.0
Rule
tavernkeeper.dynamic-execution.javascript-eval
File role
test
Source
apps/web/src/lib/experience-bridge.test.ts:421

Gitleaks reported generic-api-key

Expected behavior · high confidence

The scanner found another instance of the same fake test secret used to check that private data stays private. It is not a real key or password.

Technical evidence

Scanner reason: Gitleaks matched secret-detection rule generic-api-key. The match applies to this repository.

Contextual assessment: The gitleaks match on line 683 of experience-service.test.ts is the same fabricated privacy marker pattern used in a queueAttachment test fixture. The test verifies that getQueuedAttachment returns only public report fields and never the hidden checkpoint. This is a synthetic test value, not a usable credential, and exists only in test code.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
gitleaks 8.30.1
Rule
generic-api-key
File role
test
Source
services/api/test/experience-service.test.ts:683

JavaScript analysis reported javascript.xray.data-exfiltration

Expected behavior · high confidence

This is a helper script that creates fake roleplay data on your own computer for testing. The flagged code simply asks the operating system where its temporary folder is, then writes made-up test files there. Nothing is sent anywhere and no private information is involved.

Technical evidence

Scanner reason: JavaScript analysis matched static JavaScript security signal javascript.xray.data-exfiltration. The match applies to this repository.

Contextual assessment: Detailed technical wording was omitted by the public report safety filter.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
javascript-analysis webcrack-2.16.0_js-x-ray-16.0.0_signatures-1_literals-1_families-1
Rule
javascript.xray.data-exfiltration
File role
tooling
Source
scripts/bench/generate-small-mock.ts:4

Credential access and network transmission in one file

Expected behavior · high confidence

The app uses a session token to authenticate requests to its own backend server for opening a folder picker and importing data. The token only goes to the app's own API as a standard login header, not to any external destination.

Technical evidence

Scanner reason: A credential source and an outbound network operation were detected in the same file.

Contextual assessment: The openNativeDialog and importStDirectoryStream functions call getMobileToken() and use the result only as a Bearer token in Authorization headers for fetch requests to the project's own gateway backend (getGatewayBaseUrl()) at /api/fs/native-dialog and /api/import/st-directory/stream. The token authenticates to the app's own API routes. It is never sent to a third-party destination, logged, or persisted to an untrusted sink. This is standard authentication for a local-first client that supports mobile/companion network access, consistent with the README's description of QR access over the network.

Impact: none · Exploitability: unlikely

Developer action: none

Scanner
tavernkeeper 5
Rule
credential-exfiltration
File role
production
Source
apps/web/src/api/import-api.ts:127

Related contextual observations

Floating npm version in CI upgrade step

low risk · high confidence

The build tool upgrades itself to whatever version is newest at run time instead of a fixed version, which is a small reliability and security hygiene issue but not a direct threat to users.

Technical assessment

The global npm upgrade uses a floating dist-tag instead of a pinned version, introducing a minor supply-chain and reproducibility weakness in the release automation environment. No attacker-controlled input reaches this step and no user-facing data flow is affected.

Impact: low · Exploitability: unlikely

Developer action: Pin the npm CLI upgrade to a specific version or narrow range for predictable and safer releases.

Sources:

User code concatenated with orchestration in same VM context

low risk · high confidence

The app combines user-written code with its own control code and runs them together in the sandbox. This is done so both are covered by the same timeout. If the sandbox were escaped, the user code could also interfere with the control code, but this does not add risk beyond the sandbox's inherent weakness.

Technical assessment

The executeDiceRoll function concatenates user-authored code with a server-generated orchestration snippet using string concatenation (code plus newline plus orchestration) before passing the combined string to runInNewContext. While the orchestration snippet is static and server-controlled, running user code and orchestration in the same context means any escape from the VM boundary by user code would also have access to the orchestration variables (__registered, __targetCheckId, __rollOutput, __rollError). This is a design tradeoff to keep the timeout envelope covering both phases, and it does not introduce a new vulnerability beyond the inherent node:vm limitation.

Impact: medium · Exploitability: plausible

Developer action: none

Sources:

Host object references in VM sandbox enable known escape techniques

low risk · high confidence

The sandbox shares certain built-in JavaScript objects with the main program. A script inside the sandbox can use these shared objects as a bridge to break out and run unrestricted code on the main program, bypassing the intended limitations.

Technical assessment

The sandbox object passes real host-context constructors (Error, Object, Array, RegExp, Map, Set, etc.) into the runInNewContext sandbox. These shared references allow sandboxed code to traverse the prototype chain to obtain the host Function constructor, which can then evaluate arbitrary host-side code. This is a well-documented limitation of node:vm. The sandbox also passes Math (which includes Math.random) even though a seeded PRNG is provided via context utility functions, which is a minor design inconsistency but not a security issue on its own.

Impact: medium · Exploitability: plausible

Developer action: If strong isolation is needed, use isolated-vm which provides a separate V8 isolate with no shared object references, or run scripts in a sandboxed child process. If the current approach is acceptable for the local-only threat model, document the limitation clearly.

Sources:

Temp directory creation in test helper is benign

low risk · high confidence

The code makes a temporary scratch folder for testing and cleans up within the local environment. Nothing sensitive leaves the machine.

Technical assessment

The helper joins a system temp path with a project-prefixed name and creates a throwaway directory for a test database. This stays within the local test environment and involves no external communication or sensitive data handling.

Impact: none · Exploitability: unlikely

Developer action: none

Sources:

Coverage and limitations

JavaScript coverage

Unresolved JavaScript stages

Tools

Limitations

Technical scan identity