T05 · Unauthorized Access and Privilege Escalation
- Location
routes/state.py:8- Finding
Unauthenticated disclosure and modification of shared chat state
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This appears to be a legitimate OpenClaw web gateway, but it under-discloses persistent household memory, weak multi-user boundaries, network exposure, and location data flows.
Use only in a trusted local environment unless you first add authentication, bind to 127.0.0.1 by default, reject client-supplied system messages, prevent users from selecting other participants' identities, disable or make memory opt-in, confirm before using stored home/work locations, restrict any Google Maps browser key, and pin reviewed dependency versions.
routes/state.py:8Unauthenticated disclosure and modification of shared chat state
routes/chat.py:19Client-supplied system messages are trusted and forwarded to OpenClaw
routes/chat.py:398Caller-controlled participant identity permits cross-user memory access
static/js/ui.js:270Private route locations and a browser API key are disclosed through Google Maps URLs
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
BASE_DIR = Path(__file__).resolve().parent
load_dotenv(BASE_DIR / ".env")
def _bool_env(name: str, default: bool = False) -> bool:
The code automatically memorizes conversational statements matching broad personal-profile patterns without any explicit memory command or user disclosure. Because these patterns include home, address, work, preferences, and activities, ordinary chat can silently become long-term profiling data.
The fact store saves subject facts, source_user values, confidence, and change history to local JSON files, but the code provides no visible warning, prompt, or explanatory documentation about this persistence. Since this is a code file performing file writes of potentially sensitive memory data, the absence of any disclosure is a quality/safety issue under the rule.
This code writes user profile data to disk, including profile fields, preferences, notes, and timestamps, but there is no confirmation prompt, visible logging/print, or explanatory comment/docstring disclosing that personal data is being persisted. Because the file itself performs safety-relevant data writes and contains no user-facing warning, it fits the missing-warning criterion for code files.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
"messages": build_messages(user=user, history=history, message=message),
}
response = requests.post(
f"{OPENCLAW_BASE}/v1/chat/completions",
headers=headers,
json=payload,
This code posts the assembled chat payload, including the user identifier and message/history content, to an external OpenClaw endpoint. There is no confirmation prompt, logging, comment, or other visible disclosure in this file warning that user-provided conversation data will be transmitted over the network.
The auto-memorization heuristics and structured-fact extractors target personal profile attributes, including address, home, work, interests, lessons, and activities, based on natural-language phrasing. This is dangerous because it silently converts normal conversation into persistent sensitive profiling without meaningful consent or strong necessity.
The route system prompt explicitly tells the model it may infer origin and destination from persistent memory or current-user context. In this application, that makes sensitive stored location data more likely to be surfaced in replies or used to generate route actions even without an explicit request for those exact values.
The handler persists personal facts such as home, work, address, likes, lessons, and activities into long-term memory, including via automatic memorization, without any visible consent, retention limit, or purpose restriction. This creates a user-profiling store of sensitive personal data that can later be surfaced to the model or used in downstream actions, increasing privacy and misuse risk.
When messages begin with memory prefixes like 'remember that', the application immediately writes structured facts or notes to persistent memory and only afterward returns a success message. There is no prior warning, consent prompt, or review step, so users may not understand that personal information is being durably retained.
The route flow can infer origin and destination from stored home/work/address memory and trigger an open_route action even when the user did not explicitly provide those sensitive locations in the current request. That turns retained private location data into actionable outputs, which can expose or operationalize sensitive movements and places.
The application builds a memory context from stored data and sends it, together with the user message and history, to an external model call. Without clear disclosure, minimization, or filtering, personal facts may be transmitted to a third-party service beyond what users expect.
The POST /api/state endpoint accepts arbitrary JSON from any caller and writes it directly to persistent state with no authentication, authorization, validation, or schema checks visible in this file. This can allow unauthorized modification, corruption, or poisoning of application state, and if other parts of the application trust that state, the impact can expand into logic abuse or downstream security issues.
The code sends the active user and full chat histories to /api/state via a POST request, but there is no visible confirmation prompt or user-facing notice indicating that conversations are being stored remotely. Because this involves transmitting potentially sensitive user message content, the lack of disclosure is a safety-relevant omission.
Clicking the clearChat button immediately empties the active user's history and persists that change, making the deletion take effect without any confirmation step or warning. This is a destructive operation affecting user data, and the code provides no user disclosure before it happens.
The template injects googleMapsEmbedApiKey into window.GATEWAY_CONFIG, making the key available to any user of the page and to any script running in the browser. Even though Google Maps Embed keys are often intended for client-side use, exposing a broadly scoped or unrestricted API key can enable unauthorized reuse, quota exhaustion, or billing abuse if referrer and API restrictions are not tightly configured.
This code reads sensitive values such as OPENCLAW_TOKEN and GOOGLE_MAPS_EMBED_API_KEY from environment variables, which falls under access to credentials. There is no confirmation prompt, logging, comment, or docstring explaining this credential access behavior anywhere in the file.
The configuration uses accented display names such as "Amélie" and "Théo", which encodes a specific locale-dependent representation in user-facing text. Under the policy provided, forcing a specific language or locale without opt-in or documented justification can be a natural-language policy issue.
The dependency is specified with a lower bound only, which allows future unreviewed Flask releases to be installed and makes builds non-reproducible. This also prevents determining whether a deployed version is affected by known Flask advisories, increasing supply-chain and maintenance risk.
Flask>=3.0.0
requests>=2.31.0
python-dotenv>=1.0.1
Flask has known advisories, and because the manifest does not pin a specific version, it is impossible to verify from this file whether the installed release is affected. The main risk here is uncertainty: deployments may resolve to insecure or inconsistent versions depending on install time and environment.
The requests package is not pinned to an exact version, so installations may resolve to different releases over time, including versions with newly introduced issues or incompatible behavior. This weakens reproducibility and makes it hard to verify whether known requests vulnerabilities are present.
Flask>=3.0.0
requests>=2.31.0
python-dotenv>=1.0.1
Requests has multiple known advisories, and without version pinning there is no way to determine whether the environment will install a safe or affected release. This creates avoidable supply-chain uncertainty and complicates vulnerability management.
Using a minimum-version specifier for python-dotenv allows uncontrolled upgrades and prevents deterministic builds. That uncertainty can expose deployments to vulnerable or untested releases without an explicit review step.
Flask>=3.0.0
requests>=2.31.0
python-dotenv>=1.0.1
python-dotenv has known advisories, and the unpinned requirement means the actual installed version cannot be verified from the manifest alone. That ambiguity increases the chance of deploying a vulnerable version and makes audits harder.
This CSS file contains a natural-language comment in French: "Correction de la bulle "Jarvis réfléchit"". Under the stated policy, forcing a specific language without user opt-in can be a locale/language policy violation, and there is no indication here that the skill is intentionally region-specific or offers language choice.
Detected: suspicious.exposed_secret_literal