Back to skill

Security audit

S2 Pet Guardian Agent (S2 宠物守护者智能体)

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a local pet-monitoring demo, but its zero-trust hardware authorization claims conflict with code that can create signing keys, overwrite the public-key trust file, and verify only part of a proposed action.

Treat this as a local research/demo skill unless the authorization model is fixed. Do not connect execute_proposal to a real feeder, lock, thermostat, or other hardware gateway until the public key is protected from writes, every security-relevant proposal field is signed, tokens expire and cannot be replayed, and pet logs have clear retention and privacy controls.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (4)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
core/s2_pet_guardian_agent.py:138
Finding

Agent Self-Issues Authorization and Overwrites the Trusted Public Key

Content
View full analysis

Vulnerability Details

File Location: core/s2_pet_guardian_agent.py, lines 138-155
Vulnerability Type: Trust-anchor replacement and authorization-boundary bypass
Risk Level: High

Vulnerable Code

python
private_key = ed25519.Ed25519PrivateKey.generate()
public_key = private_key.public_key()

os.makedirs(os.path.join(os.getcwd(), "s2_bas_governance", "keys"), exist_ok=True)
with open(os.path.join(os.getcwd(), "s2_bas_governance", "keys", "lord_ed25519_public.pem"), "wb") as f:
    f.write(public_key.public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo
    ))

payload_to_sign = f"{proposal['proposal_id']}::{proposal['strategy']['target_val']}".encode('utf-8')
mock_signature = private_key.sign(payload_to_sign)
mock_dispatch_token = base64.urlsafe_b64encode(mock_signature).decode('utf-8')

agent.execute_proposal(proposal, mock_dispatch_token)

Technical Analysis

The executable entry point generates an Ed25519 private key inside the agent, derives a corresponding public key, overwrites lord_ed25519_public.pem, signs its own proposal, and validates the resulting signature.

This defeats the stated trust model in which only an external owner is supposed to possess signing authority. Verification provides no security if the component requesting authorization can also replace the verification key and generate the matching signature.

The write also conflicts with the permission declaration in SKILL.md, where s2_bas_governance/keys/*public*.pem is described as read-only. Skill metadata alone does not enforce operating-system permissions, and the implementation explicitly writes into that directory.

With the currently hard-coded telemetry, the critical-health branch returns an alert before this demonstration branch is reached. Therefore, the vulnerable path is dormant in the default run. It becomes reachable when telemet ...[truncated 1400 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove all private-key generation, proposal signing, and trust-anchor writes from production agent code.
  2. Store the trusted owner public key in an administrator-controlled location that is not writable by the agent process.
  3. Enforce the boundary with operating-system permissions, separate service accounts, container mounts, or a hardware-backed trust store; do not rely solely on Skill metadata.
  4. Refuse to start if the public key has unsafe ownership or write permissions.
  5. Move demonstration signing into a separate test module that uses a temporary directory and cannot communicate with physical hardware.
  6. Inject a test public key directly into test code instead of replacing the production trust-anchor file.
  7. Consider pinning the expected public-key fingerprint in trusted configuration and verify it before every authorization check.

T09 · Insecure Skill Coding Practices

Error
Location
core/s2_pet_guardian_agent.py:101
Finding

Signature Does Not Authenticate All Security-Relevant Proposal Fields

Content
View full analysis

Vulnerability Details

File Location: core/s2_pet_guardian_agent.py, lines 101-118
Vulnerability Type: Incomplete cryptographic message binding
Risk Level: High

Vulnerable Code

python
with open(public_key_file, "rb") as key_file:
    public_key = serialization.load_pem_public_key(key_file.read())

payload = f"{proposal['proposal_id']}::{proposal['strategy']['target_val']}".encode('utf-8')
signature = base64.urlsafe_b64decode(signature_b64.encode('utf-8'))

public_key.verify(signature, payload)
print(
    f"Authorized for pet {proposal['pet_did']} "
    f"with amount {proposal['strategy']['target_val']}g"
)
return True

The final logging statement above is rendered in English for report readability; the security-relevant behavior is the use of unsigned proposal fields after verification.

Technical Analysis

The signed payload contains only:

  • proposal_id
  • strategy.target_val

It does not authenticate the following security-relevant fields:

  • target_subsystem
  • pet_did
  • strategy.action
  • strategy.reasoning
  • status

Ed25519 guarantees the integrity of only the exact bytes passed to verify. Consequently, successful verification does not establish that the owner approved the action, subsystem, pet identity, or status present in the submitted proposal.

If downstream integration uses these unsigned fields after execute_proposal returns True, an attacker can preserve the two signed values while substituting other proposal properties.

Attack Path

  1. Obtain a valid proposal and owner signature for a particular proposal ID and target value.
  2. Keep proposal_id and strategy.target_val unchanged.
  3. Modify one or more unsigned fields, such as strategy.action, target_subsystem, or pet_did.
  4. Submit the altered proposal with the original valid signature.
  5. The implementation reconstructs the same two-field payload.
  6. Ed25519 v ...[truncated 703 chars]
Remediation
View remediation

Remediation Suggestions

  1. Define a versioned authorization schema containing every security-relevant field.
  2. Include at least the proposal ID, pet DID, target subsystem, action, target value, issuer, issued-at time, expiry time, and a cryptographically random nonce.
  3. Serialize the complete object using a deterministic canonical format, such as RFC 8785 JSON Canonicalization Scheme or a strictly specified binary encoding.
  4. Sign and verify the canonical serialized bytes rather than constructing an ambiguous delimiter-separated string.
  5. Validate field types, allowed actions, value ranges, and subsystem identifiers before signature verification.
  6. After verification, execute only the values extracted from the authenticated canonical object. Do not combine signed data with fields from an unauthenticated proposal object.
  7. Add negative tests proving that changing any security-relevant field invalidates the signature.

T09 · Insecure Skill Coding Practices

Warning
Location
core/s2_pet_guardian_agent.py:81
Finding

Valid Authorization Tokens Can Be Replayed

Content
View full analysis

Vulnerability Details

File Location: core/s2_pet_guardian_agent.py, lines 81-89 and 113-118
Vulnerability Type: Missing freshness and one-time-use enforcement
Risk Level: Medium

Vulnerable Code

python
proposal = {
    "proposal_id": f"FEED-{int(datetime.now().timestamp())}",
    "target_subsystem": "Smart_Feeder_SOHO_V1",
    "pet_did": self.pet_did,
    "strategy": {
        "action": "DISPENSE_FOOD",
        "target_val": target_amount,
        "reasoning": pet_intent
    },
    "status": "PENDING_AUTHORIZATION"
}
python
payload = f"{proposal['proposal_id']}::{proposal['strategy']['target_val']}".encode('utf-8')
signature = base64.urlsafe_b64decode(signature_b64.encode('utf-8'))

public_key.verify(signature, payload)
return True

Technical Analysis

The authorization payload has no expiration time, issued-at validation, challenge, session binding, or cryptographically random one-time nonce. The implementation also does not record a proposal as consumed after successful verification.

The proposal ID uses a timestamp with one-second resolution. This is predictable and may collide when multiple proposals are generated within the same second. More importantly, the ID is never checked against a persistent one-time-use registry.

A cryptographic signature remains valid indefinitely unless the application separately enforces freshness and consumption. Repeating the same proposal and signature therefore produces repeated successful verification.

Attack Path

  1. Observe, intercept, or otherwise obtain one legitimate proposal and its valid dispatch token.
  2. Submit the proposal and token once; verification succeeds.
  3. Submit the identical proposal and token again.
  4. No expiry, nonce-consumption, or prior-use check rejects the second request.
  5. Repeat the request as many times as the surrounding gateway permits.
  6. If each successful verification trigger ...[truncated 541 chars]
Remediation
View remediation

Remediation Suggestions

  1. Generate proposal IDs with a cryptographically secure random value, such as secrets.token_urlsafe() or a UUID generated from a secure random source.
  2. Include an issued-at timestamp, short expiration timestamp, and unique nonce in the signed payload.
  3. Enforce an acceptable clock-skew window during verification.
  4. Atomically store consumed proposal IDs or nonces in durable storage before triggering the physical action.
  5. Reject expired, previously consumed, duplicated, or unknown proposal identifiers.
  6. Couple authorization consumption and hardware dispatch in one transaction or idempotent workflow to prevent race-condition replays.
  7. Add concurrency tests in which multiple requests submit the same token simultaneously; only one request should succeed.

T08 · Insecure Dependencies

Note
Location
requirements.txt:2
Finding

Python Dependency Is Not Reproducibly Pinned

Content
View full analysis

Vulnerability Details

File Location: requirements.txt, line 2
Vulnerability Type: Unbounded dependency update and non-reproducible installation
Risk Level: Low

Vulnerable Code

text
cryptography>=41.0.0

Related installation configuration appears in package.json:

json
{
  "scripts": {
    "install": "pip install -r requirements.txt"
  },
  "dependencies": {
    "cryptography": ">=41.0.0"
  }
}

Technical Analysis

The lower-bound-only version constraint permits any future release of cryptography to be installed. There is no lock file and no package hash validation. As a result, two installations of the same project revision can resolve to different dependency artifacts.

No malicious package is present in the audited repository, and cryptography is not a typosquatted package. The issue is that the installation policy automatically trusts future versions that were not part of this audit.

Attack Path

  1. A user runs the documented installation command.
  2. The package resolver selects the newest release satisfying the lower bound.
  3. That release may differ from the version tested or audited by the project.
  4. If a permitted future release or distribution artifact is compromised, its installation or runtime behavior executes in the user's environment.
  5. The project has no hash or lock-file control to detect the unexpected artifact.

Impact Assessment

The potential privilege scope is that of the account running pip install and the Python application. A compromised dependency could execute code during installation or application startup.

This audit found no evidence that the current dependency is malicious. The confirmed weakness is non-reproducible and insufficiently constrained dependency resolution, rather than an active supply-chain compromise.

Remediation
View remediation

Remediation Suggestions

  1. Pin cryptography to a specific version that has been tested and audited.
  2. Generate a lock file using a controlled dependency-management process.
  3. Record hashes for all resolved wheels and source distributions.
  4. Install with hash enforcement, such as pip install --require-hashes -r requirements.txt.
  5. Prefer prebuilt wheels from the official package index and restrict package-index configuration to approved repositories.
  6. Use automated dependency monitoring to review security advisories and deliberately update the pin after testing.
  7. Keep the Python dependency declaration in one authoritative location to avoid drift between requirements.txt and package.json.
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (15)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The README explicitly states that pet emotion logs and feeding history are stored locally, but it does not warn users that these records can reveal behavioral patterns, occupancy habits, and potentially sensitive household information. In a smart-home/pet-monitoring context, even local-only storage can create privacy risk if files are unencrypted, overly retained, or accessible to other local users/processes.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

User-facing comments, logs, status messages, and defaults are consistently presented in Chinese, and the skill provides no opt-in or alternative language path. Under the policy, forcing a specific language without user choice is a natural-language policy violation unless the locale restriction is clearly documented and justified.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The code persistently writes companion records containing pet identifiers, nickname, timestamps, and inferred behavioral/health-related content to disk under the current working directory without consent, retention controls, or access restrictions. In a local multi-user or shared environment, this can leak sensitive household and pet data and create an unintended audit trail.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The docstring at L102 says the component only reads a public key for signature verification and 'absolutely never touches private keys.' However, the same file's main demonstration block generates an Ed25519 private key at L143 and uses it to sign a payload at L152. This is an active contradiction between the code documentation and the code behavior in the file.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The generated SKILL.md content is entirely in Chinese and presents the skill description and operating instructions in that language, with no indication that language selection is optional. This creates a natural-language locale policy concern because the skill appears to impose a specific language without user opt-in or justification.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The generated SKILL.md asserts security properties around zero-trust operation, token verification, and limits on physical intervention, but this Python generator only emits documentation text and contains no technical enforcement. If downstream systems or users rely on these claims, an agent could be deployed with implied authority boundaries that are not actually implemented, creating a dangerous documentation-to-enforcement gap.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This code performs filesystem writes to fixed paths in the current working directory and will overwrite existing SKILL.md and _meta.json files. Although there is a success print after completion, there is no prior warning, confirmation, or overwrite notice before the safety-relevant file modification occurs.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
79% confidence
Finding

The description says the agent 'only supports public-key signature verification' and 'does not touch any private keys,' which frames the skill as narrowly verification-focused. However, the package metadata also declares a directory used for persisting pet time-series records, indicating a broader stateful data-management role than the verification-only wording suggests.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The package description is entirely in Chinese and states the skill's behavior without offering any language choice or indicating that the skill is region-specific. Under the policy, forcing a specific language or locale without user opt-in is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Scope Creep

Low
Category
Excessive Agency
Confidence
70% confidence
Finding

Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Content

Scanner excerpt · LICENSE.md (reported line 12)May include surrounding context.

md
Permission is hereby granted, free of charge, to any person obtaining a copy of this Software for **personal, academic, and non-commercial research purposes**. You may modify, run, and evaluate the Software locally within your own private residential spaces.

### 2. Commercial Use & Integrators (Restricted Tier)
**Strictly Prohibited without Explicit Authorization:** Any use of this Software for commercial purposes—including but not limited to system integration (SI), deployment in commercial buildings, real estate projects, commercial veterinary clinics, or offering the Software as a SaaS/PaaS service—is strictly prohibited without a formal commercial license from Space2.world.

### 3. Identity and Addressing Standards (SUNS & S2-DID)
The algorithms governing the generation of SUNS physical addresses and 22-digit S2-DID identities are proprietary to the S2 ecosystem. You may not extract, reverse-engineer, or establish competing registry networks using these protocols.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
73% confidence
Finding

The skill content is written primarily in Chinese with some English phrases, but it does not state whether language is configurable or intended for a specific audience. This can create a language-policy issue if users are implicitly forced into a language or mixed-locale experience without opt-in.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The main demonstration flow creates a keys directory and writes lord_ed25519_public.pem to disk. Although this is non-destructive and part of a demo, the code does not warn the user that running the script will create local files under s2_bas_governance/keys.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
75% confidence
Finding

The visible purpose statement focuses on architectural/security properties and cryptographic verification constraints, not on maintaining persistent pet records. Declaring persistence in pets/* expands the apparent behavior beyond what a reader would infer from the description alone.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The dependency is specified as cryptography>=41.0.0, which allows resolution to any future version and does not guarantee reproducible or reviewed builds. This increases supply-chain risk because different environments may install different releases, including newly introduced vulnerable or incompatible versions, and makes it harder to verify what was actually deployed.

Content

Scanner excerpt · requirements.txt (reported line 2)May include surrounding context.

text
# S2-Pet-Guardian-Agent Core Dependencies
cryptography>=41.0.0

Unverifiable Dependency: cryptography has 16 known advisory(ies) (GHSA-39hc-v87j-747x (Vulnerable OpenSSL included in cryptography wheels); CVE-2023-50782 (Python Cryptography package vulnerable to Bleichenbacher timing oracle attack); GHSA-537c-gmf6-5ccf (Vulnerable OpenSSL included in cryptography wheels) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.