Skip to content

Security: KeilerHirsch-Labs/schroedinger-sync

Security

SECURITY.md

Security Policy & Threat Model

Schroedinger Sync reads a Windows DPAPI-protected Claude Desktop cookie store and uses the recovered sessionKey to authenticate an export session against claude.ai. That is a credential-sensitive operation and deserves the same scrutiny as any software that reads browser/application authentication material.

The design below reduces specific risks. It does not turn credential access into a generally safe primitive, prove the absence of exfiltration paths, or protect against an attacker who already controls the same Windows user context.

Trust boundaries and design constraints

1. Current-user credential scope

The implementation resolves Claude Desktop data from the current process user's profile and uses Windows DPAPI to recover the corresponding key material. loadMasterKey() and readSessionKey() therefore operate on the profile selected by the current Windows environment and on the Claude Desktop account represented by that profile.

This is a useful same-user design constraint, not a claim that the program can never be repurposed or that DPAPI protects a user from malicious code already executing as that same user. Review main.go and the platform assumptions in this document before treating the boundary as stronger than it is.

2. Visible browser session

The current CDP path launches Chrome with chromedp.Flag("headless", false). TestHeadlessIsHardcoded checks for that literal configuration and rejects the specific environment/CLI override patterns covered by the test.

A visible browser makes the normal export workflow observable to the interactive user and is part of the current design. It is not proof that every invocation must always be noticed, nor is it a general defense against an attacker who already controls the desktop/session.

3. Network destinations

The intended application traffic is limited to the authenticated claude.ai workflow. The current implementation uses literal chromedp.Navigate destinations and same-origin relative fetch paths; TestNetworkEgressIsClaudeOnly scans the production Go source for the call patterns it knows about and fails if the covered literals point outside claude.ai.

That test is a regression tripwire, not whole-program information-flow analysis. It does not prove that a future variable-built URL, new networking library, browser extension, proxy, compromised dependency, or surrounding OS/browser environment cannot send data elsewhere.

The project currently has no telemetry or intentional third-party upload path. Treat that as an implementation property to review, not as an unconditional guarantee about every runtime component around the process.

4. Credential output and redaction

After readSessionKey() recovers the session key, the value is registered with the redaction layer in security.go. The program routes the output paths it controls through that redaction logic, including the stdout redactor and the documented daemon/probe logging paths.

TestRedactionScrubsRegisteredSecret and TestStdoutRedactorSurvivesSplitWrites exercise selected redaction behavior, including the split-write regression. These tests do not prove that the credential is unobservable everywhere: the session key must exist in process memory while it is in use, the browser receives it as an authentication cookie, and an attacker/debugger with sufficient same-user access can inspect process/browser state outside the redactor's scope.

Since v2.2.0, the mutable AES master-key buffer and raw decrypted plaintext buffer are passed to zeroBytes after their last intended use in readSessionKey(). The returned immutable Go string remains available for the active session and in the redactor registry as needed. Buffer zeroing narrows retention for those specific mutable slices; it is not a general process-memory erasure guarantee.

5. Decryption scope versus copied cookie database

readSessionKey() queries and decrypts the sessionKey cookie row needed by the current CDP workflow rather than intentionally decrypting the full Claude cookie jar.

copyCookieDB() nevertheless copies the entire encrypted Chromium Cookies SQLite database (and available sidecars) into a temporary directory so it can be read without the live-file locking problem. That temporary copy can contain encrypted cookies for multiple domains. Cleanup is best-effort and can be interrupted by process termination or system failure.

So the precise claim is:

  • the current code intentionally decrypts one cookie row for the export workflow;
  • it may temporarily copy a broader encrypted cookie database on disk;
  • process/browser state still contains the active session credential while the session is running.

6. Package surface

The production Go files remain in package main. TestNoImportableCookiePackage checks that property. This keeps the current credential/browser implementation out of a normal importable Go library surface.

It does not prevent copying, forking, modification, or reuse of source code under the applicable license.

7. Retry and rate-limit behavior

getWithRetry applies backoff when the application receives the rate-limit error patterns it recognizes. This is intended to make legitimate exports less aggressive during transient throttling.

Backoff is not an abuse-prevention security boundary and should not be described as one. Server-side controls remain the authority for service rate limits.

What the security tests actually establish

The security-focused tests are regression tripwires for selected properties of the current implementation.

Examples:

  • TestHeadlessIsHardcoded checks for the current headless=false literal and the specific override patterns implemented by the test.
  • TestNetworkEgressIsClaudeOnly checks the literal navigation / covered helper-call patterns it scans; it is not a general static analyzer.
  • redaction tests exercise registered test values through specific output paths.
  • zeroing tests check selected mutable buffers and source-level cleanup calls.
  • TestNoImportableCookiePackage checks that production Go source remains in package main.

A passing suite means those tested properties passed under that test implementation. It does not certify the application, prove the absence of vulnerabilities, or prove every possible runtime information flow.

If a security assumption changes, update the implementation, tests, and this document together.

Threats outside this model

This project does not claim to defend against every condition in the surrounding environment. Important examples include:

  • malware or an operator already executing with the same Windows user privileges;
  • debugger/process-memory capture;
  • a compromised browser, browser extension, dependency, proxy, DNS/network layer, or operating system;
  • unauthorized publication of exported Markdown or copied temporary files after the tool writes them;
  • modified forks or binaries that do not match this repository/release;
  • future Claude Desktop or Chromium storage/authentication changes that invalidate the assumptions documented here.

Why there is no "ethical use only" license clause

The project does not rely on an ethical-use sentence as a technical security control. Licensing and threat modeling solve different problems. The useful controls here are the implementation constraints, tests, reviewable source, and explicit scope described above.

Users remain responsible for operating the tool only on accounts, machines, and data they are authorized to access.

Licensing model

The public project is licensed under AGPLv3. A separate commercial-license path is documented in COMMERCIAL-LICENSE.md for use cases that require different licensing terms.

Do not infer support levels, warranties, future enterprise features, or permanent pricing/availability promises from this threat model. Those are product/licensing decisions and should only be stated where they are actually offered and documented.

Provider scope

Claude/Anthropic is the currently implemented provider in this repository. Support for any additional provider should be treated as future work until code, tests, and documentation for that provider exist.

Each additional authentication/storage model would require its own threat-boundary review rather than inheriting the Claude assumptions automatically.

Reporting a vulnerability

Use GitHub's private vulnerability-reporting / Security Advisory path for this repository when available. Do not place credentials, cookies, private exports, exploit details, addresses, machine identifiers, or unrelated personal data in a public issue.

If a minimal public issue is necessary to establish contact, keep it free of sensitive details and request a private channel.

Supported versions

Version Status
v2.x (CDP-based) Current supported line
v1.x (tls-client impersonation) Superseded / unsupported

There aren't any published security advisories