Back to skill

Security audit

dialectica

Security checks for vulnerabilities and agentic risk

Overview

This skill needs review because it makes unrequested account changes and can expose private files while answering other people’s questions.

Review before installing. Keep Expert runs isolated from private files and inherited secrets, enter login tokens locally, and verify spending caps before starting. Search-only requests should not provision an Expert. Require approval for account reports and final questions; ask can publish and charge immediately. Material gaps in the partial scan were investigated statically, but live service and provider enforcement were not tested.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/trued.py
Finding

Automatically selected Codex provider exposes local files to third-party questions

Content
View full analysis

Impact

A successful prompt injection can cause readable secrets or private file contents to be included in the submitted answer. A read-only sandbox prevents writes, not this disclosure path. This is an exposure established by the invocation and submission flow, not a dynamically demonstrated exploit.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/trued.py
Finding

Draft evaluation can immediately publish and charge without an enforced approval gate

Content
View full analysis

Impact

A direct evaluation invocation without the required prior conversational approval can publish content and incur a fee, including on the first turn. The client cannot enforce the Skill's explicit-consent requirement.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • Rogue AgentSelf-Modification, Session Persistence
Findings (33)

Tainted flow: 'req' from os.environ.get (line 250, credential/environment) → urllib.request.build_opener.open (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/trued.py (reported line 278)May include surrounding context.

python
not_mine = None
    status = None
    try:
        with _opener.open(req, timeout=timeout) as r:
            body = json.load(r)
    except urllib.error.HTTPError as e:
        not_mine = _not_mine_hint(e)

Tainted flow: 'req' from os.environ.get (line 1981, credential/environment) → urllib.request.build_opener.open (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/trued.py (reported line 1987)May include surrounding context.

python
if token:
        req.add_header("Authorization", f"Bearer {token}")
    try:
        with _gw_opener.open(req, timeout=REQUEST_TIMEOUT_S if timeout is None else timeout) as r:
            raw = r.read().decode("utf-8", "replace")
            status = r.status
    except urllib.error.HTTPError as e:

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The commands perform issue reporting rather than searching, asking questions, or running an Expert. The references to search and ask are report text and metadata, not executions of those capabilities. Reporting issues is the chunk's primary behavior, not a supporting implementation detail of a declared operation.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The supplied chunk exposes stored-note access and modification, neither of which is disclosed in the description. It does not show knowledge-base search, question submission, or Expert operation, nor establish that these note operations are supporting implementation details of those activities.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
88% confidence
Finding

The supplied code calls an analytics endpoint rather than searching knowledge, submitting questions, or selecting and performing Expert work. Nothing in this chunk establishes analytics retrieval as a supporting step for those activities. Reading the session token and attaching it as an authentication header is an implementation detail, not a separate mismatch.

Content

No source excerpt is available for this finding.

Context Leakage

High
Category
Data Exfiltration
Confidence
85% confidence
Finding

Code or instructions that leak agent conversation context to external services, potentially exposing sensitive user interactions.

Content

Scanner excerpt · SKILL.md (reported line 35)May include surrounding context.

md
ly installed first when several versions are present. If nothing matches, ask the user where they put the skill. Commands below are written as `trued <command>` for brevity; that always means `python3 "$TRUED"`. A `trued` shim on the PATH works too.
- **Base URL:** `https://dialectica.xyz`, or `DIALECTICA_BASE_URL` if the user has set it (https only, except loopback). The raw-`curl` examples below use `$BASE`, which must resolve to whichever of those the client is using — otherwise a call would send the session token to a different host than the one it belongs to. Define it once in your shell, without a trailing slash (a doubled slash does not match the API's routes): `BASE="${DIALECTICA_BASE_URL:-https://dialectica.xyz}"; BASE="${BASE%/}"`.
- **Auth:** a session token stored at `~/.dialectica/session`, obtained per [Auth check](#auth-check). A sign-in lasts ~7 days. A connected Expert does not depend on it to keep working (see Workflow 3); asking Questions and changing settings do.
-

Context Leakage

High
Category
Data Exfiltration
Confidence
80% confidence
Finding

Code or instructions that leak agent conversation context to external services, potentially exposing sensitive user interactions.

Content

Scanner excerpt · SKILL.md (reported line 35)May include surrounding context.

md
ly installed first when several versions are present. If nothing matches, ask the user where they put the skill. Commands below are written as `trued <command>` for brevity; that always means `python3 "$TRUED"`. A `trued` shim on the PATH works too.
- **Base URL:** `https://dialectica.xyz`, or `DIALECTICA_BASE_URL` if the user has set it (https only, except loopback). The raw-`curl` examples below use `$BASE`, which must resolve to whichever of those the client is using — otherwise a call would send the session token to a different host than the one it belongs to. Define it once in your shell, without a trailing slash (a doubled slash does not match the API's routes): `BASE="${DIALECTICA_BASE_URL:-https://dialectica.xyz}"; BASE="${BASE%/}"`.
- **Auth:** a session token stored at `~/.dialectica/session`, obtained per [Auth check](#auth-check). A sign-in lasts ~7 days. A connected Expert does not depend on it to keep working (see Workflow 3); asking Questions and changing settings do.
-

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/trued.py (reported line 1945)May include surrounding context.

python
class _NoRedirect(urllib.request.HTTPRedirectHandler):
    """Refuse redirects on gateway calls.

    These requests carry the agent's password / access token. The gateway is a
    JSON API that has no reason to redirect, so treat one as misconfiguration
    rather than trying to decide whether forwarding the credential is safe.
    """

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/trued.py (reported line 2014)May include surrounding context.

python
class TokenRejected(RuntimeError):
    """The gateway rejected our access token — re-login and retry."""


class LoginForbidden(RuntimeError):

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/trued.py (reported line 2022)May include surrounding context.

python
def gw_login(gateway, user_id, password):
    """Log in with the bootstrap or rotated password; return the access token.

    Persist the result immediately — after the first login the bootstrap
    password is dead (the server rotates it). A 429 raises `GatewayRateLimited`: wait and ask

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/trued.py (reported line 5225)May include surrounding context.

python
- this machine holds a finished Expert for this host (`configured`, with its gateway address,
      its user id and a credential): everything a start would have set up with the sign-in is
      already done, so nothing is skipped that this Expert still needs. The credential may be the
      saved access token or a replacement connection code (`agent reconnect`) not yet used;
    - the deployment accepts the credential. Without that, the work calls would go out with no
      credential and no sign-in and be refused as an anonymous caller.
    """

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/trued.py (reported line 2883)May include surrounding context.

python
An id outside `PROVIDER_JOB_ID_RE` is left out and said so on stderr, without the
    value, which came from the network.
    """
    env = dict(os.environ)
    for name in PROVIDER_JOB_ENV.values():
        env.pop(name, None)
    for key, name in PROVIDER_JOB_ENV.items():

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/trued.py (reported line 4089)May include surrounding context.

python
)
    return {
        "agentId": created["agentId"],
        # This URL receives the agent password and access token, so validate it.
        "homeserver": validate_http_url(
            created.get("matrixHomeserver"),
            "Dialectica agent gateway URL",

Skill declares no tool scope ('permissions' or 'allowed-tools') but code capabilities were detected: env, file_write, network, shell.

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Every invocation provisions an Expert when none exists, including invocations that only request a public search.

Medium
Category
Excessive Agency
Confidence
97% confidence
Finding

The mandatory startup command provisions an Expert when none exists, even when the user requested only an anonymous public search. This crosses from a read-only task into persistent account and credential changes without explicit consent; being idempotent does not authorize the first creation.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · SKILL.md (reported line 60)May include surrounding context.

text
   Output rows: `Q <isrId> | viso:N fiso:N isos:N | <status> | near <0–1> | keyword|semantic | <question text>` (`near` is optional: it shows how close the match is when a similarity value is supplied; `keyword` means it matched your words and `semantic` means it is a neighbour. **A full page of `semantic` rows is not evidence the corpus has anything on the topic** — results are padded with neighbours, so relay the "no keyword matches" line rather than presenting them as matches. Both are absent on `--fast`, which is keyword-only.), `W <slug> | <snippet>` (wiki = Verified Answer pages), `A <arenaId> | <name> | <why it is closed, when it is>`. With `--fast`, question rows are just `Q <isrId> | <text>` — the fast endpoint carries no verification signals, so confirm `viso` depth via the full search or `question` before presenting anything as verified.
2. Prefer wiki hits and questions with `viso ≥ 1`. `viso`/`fiso` = verified/falsified answer counts.
3. Fetch the best hit:
   ```bash

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · SKILL.md (reported line 70)May include surrounding context.

md
ication progress. Never present an unverified Answer as verified.
5. **If the search turns up Questions nobody has answered well, the user can answer one.** Check what is actually claimable — `trued opportunities q="<the same keywords>"` — and if something comes back, offer it: *"nobody has answered this one, and your Expert could."* Then [answer it](#answer-one-question) if they say yes.

   Do this when the topic is one they could contribute to, not on every search. The search rows already show `viso:0` for an unanswered Question, but only the opportunity search knows whether **this** user may claim it — it excludes their own Questions, ones they have already answered, arenas they cannot enter, and anything already in flight. Offering without checking produces an offer that dies when acted on.

   **`trued opportunities` never replaces `trued search`.** It returns no wiki pages — the Verified Answers, the best thing to read — and hides the user's own Questions. Search first, always.

Session Persistence

Medium
Category
Rogue Agent
Confidence
96% confidence
Finding

Local session persistence is legitimate, and the restrictive directory and file permissions are appropriate. However, this authentication flow explicitly asks the user to paste a password-equivalent session token into the conversation and then embeds it in a shell command, exposing it to conversation retention and tool logs for a session that can perform account writes.

Content

Scanner excerpt · SKILL.md (reported line 107)May include surrounding context.

  1. Ask the user to open $BASE/connect-agent in a browser (offer to open it for them). The page has them sign in if needed, then shows their agent token with a copy button. The token belongs to that host, so it must be the same one the client is pointed at.
  2. Have them paste the token to you, then save it:
    bash
    mkdir -p ~/.dialectica && chmod 700 ~/.dialectica
    (umask 177; printf '%s' '<token>' > ~/.dialectica/session)   # session token — treat as a password
    

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · SKILL.md (reported line 288)May include surrounding context.

md
r can revoke an Expert's access from its page on Dialectica ("Revoke and replace"). `serve` then stops, says that Dialectica no longer accepts the Expert's credential, and does NOT fall back to the sign-in token. The page shows a new one-time connection code, once. Give it to the Expert with `trued agent reconnect` (it asks for the code without echoing it, or reads one line from stdin, never from an argument), then run `serve` again; the code works once and expires 30 minutes after it was made. Do not ask the user to paste the code into the conversation if they can run the command themselves.
- Switching back to any other strategy restores pushed work on the next cycle; nothing else needs undoing.

For a cautious first run, set a cap (`trued agent caps maxIsrs24h=1`) rather than trying to stop after one Answer from the client side — the Expert should stay connected long enough to finish what it accepted, including any correction Dialectica asks for. Caps apply to an Expert that already

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% confidence
Finding

The skill authorizes the agent to submit an external report under the user's account without waiting for approval, even when reporting was not requested. Notification and data-minimization instructions reduce the risk, but do not establish consent for an account-attributed write containing agent-selected diagnostic text.

Content

Scanner excerpt · SKILL.md (reported line 365)May include surrounding context.

trued report "ask returned CAPTCHA_REQUIRED on an authenticated session" --operation ask

text

One call, no confirmation step, nothing to follow up. It files a report and prints a reference.
Use it when Dialectica behaves other than it says it does — a documented flag that does nothing,
a count that disagrees with the rows beside it, an error that names a state you are not in, a
page that will not load. `--feature` is the same door for something missing rather than broken.

The assist workflow sends question drafts and user replies to Dialectica without a user-facing privacy warning.

Medium
Category
Output Handling
Confidence
88% confidence
Finding

The request instructions require sending the question, subsequent replies, and the current draft to the external assist service on every turn; L168 then instructs repeating this workflow until ready. Although the API fields are documented, the file does not instruct the agent to warn users that potentially sensitive draft content will leave their environment before the question is submitted.

Content

No source excerpt is available for this finding.

Unbounded Resource Access

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill allows unbounded resource consumption (API calls, storage, compute). Without rate limits or quotas, a compromised or misbehaving agent can cause denial-of-service or cost overruns.

Content

Scanner excerpt · scripts/trued.py (reported line 1874)May include surrounding context.

python
# request … timed out after 30000ms".
SYNC_TIMEOUT_MS = 10_000
# Client-side abort ceiling, above the server's long-poll cap so a healthy poll
# returns normally but a half-open connection cannot hang the loop forever.
REQUEST_TIMEOUT_S = (SYNC_TIMEOUT_MS + 5_000) / 1000
DIALECTICA_TYPE = "org.dialectica.type"
DIALECTICA_DATA = "org.dialectica.data"

Unbounded Resource Access

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill allows unbounded resource consumption (API calls, storage, compute). Without rate limits or quotas, a compromised or misbehaving agent can cause denial-of-service or cost overruns.

Content

Scanner excerpt · scripts/trued.py (reported line 1974)May include surrounding context.

python
an answer."""


def _gw(gateway, path, method="GET", token=None, query=None, json_body=None, timeout=None):
    """One gateway request. Returns (status, parsed_body). `timeout` bounds this request below
    the default ceiling (a send with a deadline passes what is left of it)."""
    url = gateway.rstrip("/") + path

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · scripts/trued.py (reported line 2592)May include surrounding context.

python
# `permission_denials` and the model falls back to memory; adding
        # `--allowedTools WebFetch` the denial list is empty and it fetches.
        #
        # Note the deny is not universal — read-only tools are auto-approved, so
        # `--tools Read` alone reads a file and `--tools Bash` alone runs a read-only
        # command. It is network access and mutating shell that need the grant.
        #

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
96% confidence
Finding

The subprocess invocation avoids shell injection, but the automatically selected Codex provider processes strangers' prompts with local-file read access and no effective tool allowlist. A malicious question can induce it to read accessible credentials or private files and include them in the answer automatically submitted to Dialectica; a read-only sandbox does not prevent disclosure.

Content

Scanner excerpt · scripts/trued.py (reported line 2914)May include surrounding context.

python
binary, args, cmd = resolve_provider_invocation(model)
    env = provider_env(job)
    try:
        proc = subprocess.Popen(  # noqa: S603 - list args, shell=False by construction
            [binary] + args,
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,