Back to skill

Security audit

Bitrix24 Skill

Security checks for vulnerabilities and agentic risk

Overview

This Bitrix24 integration skill is mostly coherent, but it needs Review because its helper scripts can use powerful CRM credentials with weak destination validation, incomplete mutation safeguards, and plaintext local state.

Review this skill before installing in a production Bitrix24 environment. Use only a test portal or least-privilege credentials, pin B24_DOMAIN to an approved HTTPS tenant, avoid broad packs unless needed, require plan-and-confirm flows for all mutations, and treat .runtime state files as sensitive because they may contain business payloads or tokens.

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 (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/bitrix24_client.py:969
Finding

Credentials and business data can be transmitted to arbitrary or plaintext endpoints

Content
View full analysis
str: domain = self.tenant.domain.strip().rstrip("/") if not domain.startswith("http://") and not domain.startswith("https://"): domain = f"https://{domain}" if self.tenant.auth_mode == "webhook": if not self.tenant.webhook_user_id or not self.tenant.webhook_code: raise ValueError("webhook_user_id and webhook_code are required for webhook mode") return ( f"{domain}/rest/" f"{self.tenant.webhook_user_id}/{self.tenant.webhook_code}/{method}" ) if rest_v3: return f"{domain}/rest/api/{method}" return f"{domain}/rest/{method}" def _post_json(self, url: str, payload: Dict[str, Any]) -> Dict[str, Any]: req = urllib.request.Request( url=url, method="POST", headers={ "Content-Type": "application/json", "Accept": "application/json", }, data=json.dumps(payload).encode("utf-8"), ) with urllib.request.urlopen(req, timeout=self.timeout) as resp: raw = resp.read().decode("utf-8") parsed = self._safe_json_parse(raw) if parsed is None: raise BitrixAPIError("Invalid JSON response", code="INVALID_JSON") return parsed ``` The destination originates directly from the environment: ```python def load_tenant_config_from_env() -> Tuple[TenantConfig, TokenStore]: domain = os.getenv("B24_DOMAIN", "").strip() auth_mode = os.getenv("B24_AUTH_MODE", "webhook").strip().lower() if not domain: raise ValueError("B24_DOMAIN is required") if auth_mode not in {"webhook", "oauth"}: raise ValueError("B24_AUTH_MODE must be 'webhook' or 'oauth' ...[truncated 2803 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/bitrix24_client.py:393
Finding

Incomplete method-risk classification bypasses write and destructive confirmation controls

Content
View full analysis
str: method_l = method.lower() if method_l == "batch": cmd = (params or {}).get("cmd", {}) if isinstance(cmd, dict): batch_risks = [ classify_method_risk(batch_command_method(v), None) for v in cmd.values() if isinstance(v, str) ] if "destructive" in batch_risks: return "destructive" if "write" in batch_risks: return "write" return "read" if DESTRUCTIVE_METHOD_RE.search(method_l): return "destructive" if WRITE_METHOD_RE.search(method_l): return "write" return "read" ``` The resulting classification controls the confirmation barriers: ```python if method_risk == "write" and not args.confirm_write: print( "Error: write method detected. Add --confirm-write to execute.", file=sys.stderr, ) raise SystemExit(2) if method_risk == "destructive" and not args.confirm_destructive: print( "Error: destructive method detected. Add --confirm-destructive to execute.", file=sys.stderr, ) raise SystemExit(2) ``` ### Technical Analysis The implementation treats every method suffix not explicitly recognized by two regular expressions as a read operation. This is a fail-open design. The project's own method catalogs contain mutating operations with suffixes outside these expressio ...[truncated 1882 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/offline_sync_worker.py:166
Finding

Full event, request, and API response payloads are persisted in plaintext

Content
View full analysis
None: """Write to DLQ with file locking to prevent corruption from concurrent writes.""" dlq_path.parent.mkdir(parents=True, exist_ok=True) row = { "tenant": tenant, "event": event_item.get("event") or event_item.get("EVENT"), "message_id": event_message_id(event_item), "retry_count": retries, "error": error, "payload": event_item, "ts": int(time.time()), } row_json = json.dumps(row, ensure_ascii=True) + "\n" with dlq_path.open("a", encoding="utf-8") as fh: fcntl.flock(fh.fileno(), fcntl.LOCK_EX) try: fh.write(row_json) fh.flush() finally: fcntl.flock(fh.fileno(), fcntl.LOCK_UN) ``` Plans retain complete method parameters: ```python plan = { "plan_id": plan_id, "tenant": tenant, "method": method, "params": params, "risk": risk, "allowlisted": bool(allowlisted), "packs": list(packs), "created_at": now, "expires_at": now + self.ttl_sec, "executed": False, } def mutate(state: Dict[str, Any]) -> Tuple[Dict[str, Any], Dict[str, Any]]: plans = state.get("plans") if not isinstance(plans, dict): plans = {} plans = self._cleanup_plans(plans, now) plans[plan_id] = plan state["plans"] = plans return state, plan ``` Idempotency records retain complete API responses: ```python def done(self, key: str, response: Dict[str, Any]) -> None: now ...[truncated 2726 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
scripts/offline_sync_worker.py:120
Finding

Offline event authentication is optional and fails open when no expected token is configured

Content
View full analysis
bool: """Validate application_token from event using constant-time comparison.""" if expected_token is None: return True # No validation configured received_token = event_auth.get("application_token") return secure_compare(received_token, expected_token) ``` The expected token is optional: ```python parser.add_argument( "--application-token", default=None, help="Expected application_token for event validation (optional)", ) ``` ### Technical Analysis Constant-time comparison is used correctly when an expected token is configured. However, the default configuration supplies no token, and the validation function explicitly accepts every event in that state. This conflicts with the project documentation's recommendation to verify `application_token` for inbound event handling. The token is also supplied through a command-line argument, which may be exposed through process listings or command history on some systems. The current default event processor is a no-op, reducing immediate impact in the unmodified baseline. The file explicitly instructs integrators to replace it with domain-specific processing, at which point the fail-open default can become security-sensitive. ### Attack Path 1. The worker is deployed without `--application-token`, which is the default documented invocation. 2. An untrusted, cross-tenant, or injected event appears in the consumed event set. 3. `validate_application_token()` receives `expected_token=None`. 4. The function returns `True` without examining the received token. 5. The worker passes the event to the configured domain-specific process ...[truncated 690 chars]
Remediation
View remediation
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
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (18)

Tainted flow: 'req' from os.getenv (line 989, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

The client builds request URLs from the tenant domain loaded from environment variables and then sends authenticated requests to that host. If an attacker can influence B24_DOMAIN or related runtime configuration, the script will transmit webhook credentials or OAuth bearer tokens to an attacker-controlled server, creating a server-side request forgery/exfiltration path. In this skill context, that is more dangerous because the tool is specifically designed to handle high-value CRM/admin API credentials and automate privileged operations.

Content

Scanner excerpt · scripts/bitrix24_client.py (reported line 998)May include surrounding context.

python
},
            data=json.dumps(payload).encode("utf-8"),
        )
        with urllib.request.urlopen(req, timeout=self.timeout) as resp:
            raw = resp.read().decode("utf-8")
            parsed = self._safe_json_parse(raw)
            if parsed is None:

Tainted flow: 'req' from os.getenv (line 989, credential/environment) → urllib.request.urlopen (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/bitrix24_client.py (reported line 1081)May include surrounding context.

python
)
    url = f"https://oauth.bitrix24.tech/oauth/token/?{query}"
    req = urllib.request.Request(url=url, method="GET", headers={"Accept": "application/json"})
    with urllib.request.urlopen(req, timeout=30) as resp:
        body = json.loads(resp.read().decode("utf-8"))

    if "error" in body:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · README.md (reported line 202)May include surrounding context.

  1. Create env:
bash
cp .env.example .env
source .env

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · README.md (reported line 203)May include surrounding context.

bash
cp .env.example .env
source .env
  1. Fill .env.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- prefer `scripts/bitrix24_client.py` and `scripts/offline_sync_worker.py`,

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- prefer `scripts/bitrix24_client.py` and `scripts/offline_sync_worker.py`,

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 · references/bitrix24.md (reported line 385)May include surrounding context.

md
| Error code | Typical reason | Action |
|---|---|---|
| `NO_AUTH_FOUND` | bad webhook/access token | verify secret/token source and env |
| `INVALID_CREDENTIALS` | user lacks permissions | adjust user role or run under correct account |
| `insufficient_scope` | missing scope | add scope and reinstall/reissue auth |
| `expired_token` | OAuth token expired | refresh via OAuth token endpoint |

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · README.md (reported line 150)May include surrounding context.

python3 skills/bitrix24-agent/scripts/bitrix24_client.py
--params ''
--allow-unlisted
--confirm-write

text

3. If it is stable and useful, add it to the right pack:

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill describes and encourages use of local scripts with capabilities for environment access, file reads/writes, and network operations, but it does not declare any explicit tool scope such as allowed tools or permissions. This creates an authority mismatch: an agent may be induced to perform sensitive actions without a clearly constrained execution boundary, increasing the risk of secret exposure, unintended file modification, or outbound requests to attacker-controlled endpoints.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The default prompt begins with "Help me build or debug...", and "help me" is a generic phrase commonly used in ordinary conversation. In a manifest file, this kind of broad invocation wording can cause unintended skill activation because it does not clearly distinguish when this specific skill should apply versus other assistance contexts.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/bitrix24.md (reported line 164)May include surrounding context.

4.3 Example: webhook call

bash
curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"fields":{"TITLE":"Lead from AI agent"}}' \
  "https://{portal}/rest/{user_id}/{webhook}/crm.lead.add"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This markdown file documents destructive operations (bizproc.workflow.terminate and bizproc.workflow.kill) but provides no warning about impact, irreversibility, or the need for careful confirmation before use. Under the markdown-file criteria, omission of warnings for behaviors that can affect workflow integrity is a reportable safety gap.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This markdown file documents methods including create, update, and destructive delete operations, but it provides no cautionary note about potential impact to user data or collaboration content. Under the markdown-specific warning criterion, descriptions covering destructive or integrity-affecting behavior should disclose those risks to users.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This markdown file documents several write operations such as adding or updating orders, payments, products, and prices, but it provides no warning that these actions can alter production commerce data. For markdown files, safety-relevant behaviors that affect user data or system integrity should be disclosed so users understand the impact before using the skill.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This markdown file describes file and document operations, including write and destructive methods such as disk.file.delete, but provides no warning about potential impacts to user data or system integrity. Under the markdown-specific warning rule, a skill description should disclose behaviors that can modify or delete data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This markdown file documents methods including write and destructive operations such as landing.site.delete and landing.landing.delete, but it does not include any warning about the potential impact on user data or site integrity. Under the markdown-specific SQP-2 criteria, descriptions that omit warnings about behaviors affecting user data or system state should be flagged.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This markdown file documents an operation that exports project status data to reporting storage, which can affect user data handling and potentially transmit or persist information elsewhere. The description provides no warning or disclosure about that behavior, which is required for markdown files when user data, privacy, or system integrity may be affected.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The manifest emphasizes designing and hardening integrations with Bitrix24 REST APIs for webhooks, OAuth, scopes, events, CRM/tasks/chats automation, and API troubleshooting. This reference chain documents registering and unregistering Bitrix24 AI engines, which is a distinct platform capability not explicitly covered by the stated purpose and goes beyond the core integration scenarios listed.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.