Back to skill

Security audit

Gemini Live Phone

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real Twilio-to-Gemini phone bridge, but it exposes internet-facing phone-call and live-audio capabilities without enough authentication, scoping, or safe deployment defaults.

Review this carefully before installing. Only run it behind strong authentication, Twilio signature validation, trusted-host enforcement, rate limits, destination and caller-ID allowlists, explicit PUBLIC_URL/TWILIO_ACCOUNT_SID/TWILIO_FROM configuration, and clear consent and privacy handling for live audio and any recording. Pin dependencies before deployment.

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

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/bridge.py:523
Finding
Unauthenticated Outbound Call Creation Using Privileged Twilio Credentials<![CDATA[ ## Vulnerability Details **File Location**: `scripts/bridge.py`, lines 523-557 **Vulnerability Type**: Missing authentication and authorization on a privileged API endpoint **Risk Level**: Critical ### Vulnerable Code ```python @router.post("/call") async def make_call(request: Request): """Initiate an outbound call via Twilio → Gemini Live.""" body = await request.json() to = body.get("to") greeting = body.get("greeting", "") from_number = body.get("from", config.twilio_from) record = body.get("record", config.default_record) if not to: return {"error": "Missing 'to' parameter"} if not twilio_client: return {"error": "Twilio client not initialized (missing auth token)"} # Build TwiML for outbound call twiml_url = f"{config.public_url}/twiml" status_url = f"{config.public_url}/call-status" try: call = twilio_client.calls.create( to=to, from_=from_number, url=twiml_url, status_callback=status_url, status_callback_event=["initiated", "ringing", "answered", "completed"], record=record, ) logger.info(f"Outbound call initiated: {call.sid} to {to}") return {"call_sid": call.sid, "to": to, "from": from_number, "status": "initiated"} except Exception as e: logger.error(f"Failed to create call: {e}") return {"error": str(e)} ``` ### Technical Analysis The `/gemini-live/call` endpoint initiates calls through a Twilio client configured with the operator's account credentials. It does not require an API key, authenticated session, signed request, or authorization decision. The request body directly controls the destination number and can also request a source number. The endpoint therefore exposes a paid, privileged telephony operation to any client that can reach the service. The bridge is documented as internet-accessible, making this defect particularl ...[truncated 1700 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require strong authentication for `/call`, such as a validated service API key, OAuth2 access token, or mutually authenticated TLS. 2. Add authorization that limits call creation to explicitly permitted users or services. 3. Do not allow callers to provide an arbitrary source number. Select it server-side from an approved configuration or validate it against a strict allowlist. 4. Validate destination numbers using a telephone-number parser and require canonical E.164 formatting. 5. Apply destination and geographic allowlists where the deployment does not require arbitrary calling. 6. Add per-principal and global rate limits, concurrent-call limits, spending controls, and anomaly alerts. 7. Return appropriate HTTP status codes without exposing raw provider exception text. 8. Add audit records containing the authenticated principal, destination, call SID, and authorization outcome. 9. Consider requiring a short-lived, purpose-bound authorization token for every outbound call request. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/bridge.py:502
Finding
Twilio WebSocket and Webhook Requests Are Accepted Without Origin Authentication<![CDATA[ ## Vulnerability Details **File Location**: `scripts/bridge.py`, lines 502-604 **Vulnerability Type**: Missing Twilio request-signature and media-stream authentication **Risk Level**: High ### Vulnerable Code ```python @router.websocket("/stream") async def websocket_stream(ws: WebSocket): """WebSocket endpoint for Twilio Media Streams.""" await ws.accept() logger.info("WebSocket connected") start_data = None call_sid = "unknown" try: # Wait for the start event while True: msg = await asyncio.wait_for(ws.receive_text(), timeout=30.0) data = json.loads(msg) if data.get("event") == "start": start_data = data.get("start", {}) call_sid = start_data.get("callSid", "unknown") logger.info(f"[{call_sid}] Stream started: {json.dumps(start_data, indent=2)}") break elif data.get("event") == "connected": logger.info("Stream connected event received") continue if start_data: await run_call(ws, start_data, config.system_prompt, config.gemini_voice, config.gemini_model, call_sid) ``` ```python @router.api_route("/call-status", methods=["GET", "POST"]) async def call_status(request: Request): """Receive Twilio call status webhooks.""" if request.method == "POST": form = await request.form() data = dict(form) else: data = dict(request.query_params) call_sid = data.get("CallSid", "unknown") status = data.get("CallStatus", "unknown") logger.info(f"[{call_sid}] Call status: {status}") # Update active call status if call_sid in active_calls: active_calls[call_sid]["status"] = status return Response(status_code=204) @router.api_route("/recording-status", methods=["GET", "POST"]) async def recording_status(request: Request): """Receive Twil ...[truncated 2553 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Validate `X-Twilio-Signature` on every Twilio HTTP webhook using Twilio's request validator and the exact externally visible URL. 2. Prefer POST-only webhook endpoints and reject unsupported content types. 3. Generate a cryptographically random, short-lived token for each expected media stream and include it in the stream URL or custom parameters. 4. Bind each token to the expected Call SID, expiration time, direction, and single-use state. 5. Do not invoke `run_call()` until the stream has been authenticated and matched to an expected call. 6. Reject unknown, expired, duplicate, or already-completed call identifiers. 7. Enforce WebSocket origin policy where applicable, while not relying on Origin alone as authentication. 8. Apply connection limits, per-message size limits, event-rate limits, strict JSON schemas, and maximum audio throughput. 9. Avoid logging complete untrusted `start_data`; log only validated fields after sanitizing control characters. 10. Close unauthenticated WebSockets with an appropriate policy-violation status before allocating Gemini resources. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/bridge.py:487
Finding
Untrusted Host Header Controls Twilio Media Stream Destination<![CDATA[ ## Vulnerability Details **File Location**: `scripts/bridge.py`, lines 487-574 **Vulnerability Type**: Host-header injection and unsafe dynamic XML construction **Risk Level**: High ### Vulnerable Code ```python @router.api_route("/incoming", methods=["GET", "POST"]) async def incoming_call(request: Request): """TwiML response for inbound calls — connects to WebSocket media stream.""" twiml = f"""<?xml version="1.0" encoding="UTF-8"?> <Response> <Connect> <Stream url="wss://{request.headers.get('host', 'athena.abfs.tech')}{config.route_prefix}/stream"> <Parameter name="direction" value="inbound" /> </Stream> </Connect> </Response>""" return Response(content=twiml, media_type="application/xml") ``` ```python @router.api_route("/twiml", methods=["GET", "POST"]) async def twiml_for_outbound(request: Request): """TwiML for outbound calls — connects to the same WebSocket stream.""" twiml = f"""<?xml version="1.0" encoding="UTF-8"?> <Response> <Connect> <Stream url="wss://{request.headers.get('host', 'athena.abfs.tech')}{config.route_prefix}/stream"> <Parameter name="direction" value="outbound" /> </Stream> </Connect> </Response>""" return Response(content=twiml, media_type="application/xml") ``` ### Technical Analysis Both TwiML-producing endpoints derive the WebSocket destination from the untrusted HTTP `Host` header. The value is interpolated directly into XML without an allowlist or XML escaping. In deployments where a reverse proxy forwards arbitrary Host headers, an attacker can influence the generated `<Stream>` URL. Twilio follows this URL when setting up the media stream, so an attacker-controlled host can become the recipient of live call audio. The same interpolation can also produce malformed XML because metacharacters are not escaped. Whether a given injected host is accepted depends on the HTTP server, reverse proxy, and Twilio URL parsing, bu ...[truncated 1382 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Never derive a security-sensitive callback or media destination from the request Host header. 2. Configure one canonical public HTTPS/WSS origin and build all TwiML URLs exclusively from that validated configuration. 3. Require `PUBLIC_URL` during startup and fail closed if it is missing or invalid. 4. Apply FastAPI or Starlette trusted-host middleware with an explicit hostname allowlist. 5. Configure the reverse proxy to reject unknown Host values and overwrite forwarded host information where appropriate. 6. Generate TwiML through Twilio's supported response-building library rather than string interpolation. 7. XML-escape every dynamic value even when it has passed semantic validation. 8. Validate the configured URL scheme, hostname, port, and path; require TLS except in explicit local development mode. 9. Add regression tests that submit malformed and attacker-controlled Host headers and confirm rejection. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/bridge.py:119
Finding
Hardcoded Twilio Account, Telephone Number, and External Deployment Defaults<![CDATA[ ## Vulnerability Details **File Location**: `scripts/bridge.py`, lines 119-130 **Vulnerability Type**: Unsafe deployment-specific defaults and undeclared external routing **Risk Level**: High ### Vulnerable Code ```python @dataclass class BridgeConfig: # Twilio twilio_account_sid: str = os.getenv("TWILIO_ACCOUNT_SID", "ACbdb5def0f217c61d3eea837e4807c0ce") twilio_auth_token: str = os.getenv("TWILIO_AUTH_TOKEN", "") twilio_from: str = os.getenv("TWILIO_FROM", "+17866558779") # Gemini gemini_api_key: str = os.getenv("GEMINI_API_KEY", os.getenv("GOOGLE_API_KEY", "")) gemini_model: str = "gemini-2.5-flash-native-audio-latest" gemini_voice: str = "Kore" # Server host: str = "0.0.0.0" port: int = 3335 public_url: str = os.getenv("PUBLIC_URL", "https://athena.abfs.tech/gemini-live") route_prefix: str = "/gemini-live" ``` The hardcoded public URL is used for privileged outbound-call callbacks: ```python twiml_url = f"{config.public_url}/twiml" status_url = f"{config.public_url}/call-status" call = twilio_client.calls.create( to=to, from_=from_number, url=twiml_url, status_callback=status_url, status_callback_event=["initiated", "ringing", "answered", "completed"], record=record, ) ``` ### Technical Analysis The application silently falls back to a specific Twilio account SID, source telephone number, and public domain. These are deployment-specific values rather than safe generic defaults. The Skill documentation's Quick Start instructs users to set `GOOGLE_API_KEY` and `TWILIO_AUTH_TOKEN`, but does not make overriding all three deployment-specific defaults a prerequisite. If an operator follows those instructions without setting `TWILIO_ACCOUNT_SID`, `TWILIO_FROM`, and `PUBLIC_URL`, outbound calls are configured to retrieve TwiML from and send call-status events to `athena.abfs.tech`. An account SID is generally an identifier rather than a secret, but hardcoding it c ...[truncated 1606 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the hardcoded Twilio account SID, source number, and public URL. 2. Require `TWILIO_ACCOUNT_SID`, `TWILIO_FROM`, and `PUBLIC_URL` as explicit deployment configuration. 3. Fail startup with a clear error if any required setting is absent. 4. Validate that the source number uses canonical E.164 format and belongs to an approved deployment allowlist. 5. Validate that `PUBLIC_URL` uses HTTPS, contains an approved hostname, and has the expected route prefix. 6. Display the resolved callback destinations at startup without disclosing credentials. 7. Update `SKILL.md` metadata and Quick Start instructions to enumerate every required environment variable. 8. Separate sample values into an example configuration file using reserved, non-operational placeholders. 9. Add startup checks that reject known sample or vendor-specific values in production mode. ]]>

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding
Open-Ended and Unhashed Python Dependency Versions Permit Unreviewed Upgrades<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt`, lines 1-7 **Vulnerability Type**: Non-reproducible dependency resolution and supply-chain exposure **Risk Level**: Medium ### Vulnerable Code ```text fastapi>=0.135.0 uvicorn>=0.41.0 google-genai>=1.60.0 twilio>=9.0.0 audioop-lts>=0.2.0 websockets>=16.0 python-multipart>=0.0.20 ``` ### Technical Analysis Every dependency is specified using an open-ended minimum version. A future installation may therefore resolve to versions that did not exist when the Skill was reviewed. No hashes or lock file are supplied to verify the exact package artifacts. The dependencies are obtained from normal third-party package infrastructure and no typosquatted package was identified in the reviewed manifest. Nevertheless, the current specification makes builds non-reproducible and allows a compromised, malicious, or incompatible future release to be installed automatically. Because these libraries execute in the same process as Twilio and Gemini credentials, a compromised dependency would inherit access to environment variables, network connections, audio data, and filesystem permissions available to the bridge. ### Attack Path 1. A maintainer publishes a future package release, or a package-distribution account is compromised. 2. The malicious or vulnerable release remains compatible with the broad `>=` constraint. 3. A user performs a fresh installation or rebuild. 4. The package resolver selects the new unreviewed version. 5. Package installation or import-time code executes in the bridge environment. 6. The compromised dependency can access API credentials, telephony metadata, live audio, and network capabilities available to the process. ### Impact Assessment A successful dependency compromise could obtain all privileges held by the bridge process, including: - Access to Twilio and Gemini credentials present in environment variables or process memory. - Interception or manipulation of live cal ...[truncated 438 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin every direct dependency to an exact, reviewed version. 2. Generate and commit a lock file that also records transitive dependencies. 3. Use package hashes, such as pip's `--require-hashes`, to verify downloaded artifacts. 4. Build dependencies through a controlled update process rather than resolving arbitrary new releases during deployment. 5. Run automated vulnerability and provenance scanning on every dependency update. 6. Review changelogs and compatibility before upgrading security-sensitive packages. 7. Use a private package mirror or artifact repository where organizational policy requires stronger supply-chain controls. 8. Rebuild and test lock files regularly so security updates can be adopted without reopening unrestricted version ranges. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (23)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The documented purpose understates the actual behavior by focusing on a call bridge while also exposing outbound call initiation and webhook handling, and the finding indicates additional recording-related behavior and embedded Twilio identifiers not disclosed in the description. That mismatch is dangerous because users may deploy a skill capable of initiating real-world telecom actions and handling sensitive call metadata without informed consent or adequate review.

Possible Typosquatting: 'uvicorn' resembles popular package 'gunicorn'

High
Category
Supply Chain
Confidence
70% confidence
Finding
Package name closely resembles a popular package, suggesting possible typosquatting. Attackers publish malicious packages with similar names to trick developers into installing them.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding
Suspicious Unicode normalization or mixed-script content

Lp3

Medium
Category
MCP Least Privilege
Confidence
74% confidence
Finding
The skill declares required environment variables and implies operational capabilities, but it does not declare an explicit tool/permission scope despite functionality that can place calls and expose networked endpoints. This weakens least-privilege review and can mislead operators about what the skill is allowed to do, especially because it bridges external communications and may write or generate runtime artifacts in practice.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill bridges live phone audio through Twilio and Google Gemini, but the documentation does not warn about privacy, data sharing, retention, or disclosure obligations. Because the content is real-time voice from phone calls, missing privacy guidance is especially risky and may lead to unlawful processing of sensitive communications data.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The documentation provides a ready-to-run API example that places outbound calls to arbitrary phone numbers but does not warn that this triggers real telephony activity with possible cost, abuse, and consent implications. In this context, omission of such warnings increases the chance of accidental or unauthorized calls from a deployed system.

External Transmission

Medium
Category
Data Exfiltration
Content
## Outbound Call API

```bash
curl -X POST https://your-domain/gemini-live/call \
  -H 'Content-Type: application/json' \
  -d '{"to": "+1234567890", "greeting": "Hello! This is Marcia."}'
```
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding
Suspicious Unicode normalization or mixed-script content

Tainted flow: 'path' from os.getenv (line 61, credential/environment) → open (file write)

Medium
Category
Data Flow
Content
if self._file:
                self._file.close()
            path = OPENCLAW_LOG_DIR / f"openclaw-{now_date}.log"
            self._file = open(path, "a", encoding="utf-8")
            self._current_date = now_date

    def emit(self, record: logging.LogRecord):
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The bridge forwards live caller audio to the Gemini API for processing, but this file does not provide any caller disclosure, consent prompt, or gating before transmission begins. In a telephony context this can create privacy, compliance, and data-handling exposure, especially for jurisdictions or deployments requiring notice before AI processing or third-party sharing of call content.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The outbound call endpoint allows recording to be enabled and then initiates Twilio recording without any user-facing disclosure or consent mechanism in the generated call flow. Recording phone calls without notice can violate legal requirements and materially increases privacy risk because sensitive voice content may be stored and retained.

Unpinned Dependencies

Low
Category
Supply Chain
Content
fastapi>=0.135.0
uvicorn>=0.41.0
google-genai>=1.60.0
twilio>=9.0.0
Confidence
97% confidence
Finding
The dependency is specified with a lower bound only, which allows future installs to resolve to different versions over time. This weakens build reproducibility and can unintentionally pull in newly introduced vulnerable or breaking releases in a network-facing FastAPI service.

Unverifiable Dependency: fastapi has 3 known advisory(ies) (CVE-2021-32677 (Cross-Site Request Forgery (CSRF) in FastAPI); CVE-2021-32677 (FastAPI is a web framework for building APIs with Python 3.6+ based on standard ); CVE-2024-24762 (FastAPI is a web framework for building APIs with Python 3.8+ based on standard )), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
90% confidence
Finding
FastAPI has known advisories, and because the manifest does not pin an exact version, it is impossible to determine from this file whether an affected release will be installed. In a public-facing API service, that uncertainty is a real dependency-risk finding even if the currently resolved version might be safe.

Unpinned Dependencies

Low
Category
Supply Chain
Content
fastapi>=0.135.0
uvicorn>=0.41.0
google-genai>=1.60.0
twilio>=9.0.0
audioop-lts>=0.2.0
Confidence
97% confidence
Finding
Using an unpinned uvicorn version permits uncontrolled dependency drift across deployments. For an internet-exposed ASGI server, this can lead to inconsistent security posture and accidental adoption of vulnerable releases.

Unverifiable Dependency: uvicorn has 4 known advisory(ies) (CVE-2020-7694 (Log injection in uvicorn); CVE-2020-7695 (HTTP response splitting in uvicorn); CVE-2020-7694 (This affects all versions of package uvicorn. The request logger provided by the) +1 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
90% confidence
Finding
uvicorn has historical security advisories, but the unpinned requirement prevents verifying whether deployments resolve to a patched version. Since uvicorn is the HTTP/WebSocket server, this ambiguity matters more than it would for a non-network-exposed library.

Unpinned Dependencies

Low
Category
Supply Chain
Content
fastapi>=0.135.0
uvicorn>=0.41.0
google-genai>=1.60.0
twilio>=9.0.0
audioop-lts>=0.2.0
websockets>=16.0
Confidence
95% confidence
Finding
The Google GenAI client is not pinned, so installations may fetch different versions over time. While not proof of an active exploit, this creates supply-chain and stability risk for a real-time voice integration that depends on predictable library behavior.

Unpinned Dependencies

Low
Category
Supply Chain
Content
fastapi>=0.135.0
uvicorn>=0.41.0
google-genai>=1.60.0
twilio>=9.0.0
audioop-lts>=0.2.0
websockets>=16.0
python-multipart>=0.0.20
Confidence
95% confidence
Finding
The Twilio SDK is specified as a minimum version only, allowing later versions to be installed without review. In a telephony bridge handling live calls, unreviewed dependency changes can affect security-sensitive request handling and authentication flows.

Unpinned Dependencies

Low
Category
Supply Chain
Content
uvicorn>=0.41.0
google-genai>=1.60.0
twilio>=9.0.0
audioop-lts>=0.2.0
websockets>=16.0
python-multipart>=0.0.20
Confidence
94% confidence
Finding
The audio processing library is unpinned, so builds are not reproducible and may pull unexpected future releases. This is a supply-chain hygiene issue rather than direct evidence of compromise, but still increases operational risk.

Unpinned Dependencies

Low
Category
Supply Chain
Content
google-genai>=1.60.0
twilio>=9.0.0
audioop-lts>=0.2.0
websockets>=16.0
python-multipart>=0.0.20
Confidence
97% confidence
Finding
The websockets package is unpinned, which allows dependency drift and makes it hard to know whether deployments include a safe version. Because this skill bridges live audio over WebSockets, predictable and patched dependency versions are especially important.

Unverifiable Dependency: websockets has 4 known advisory(ies) (CVE-2018-1000518 (websockets is vulnerable to denial of service by memory exhaustion); CVE-2021-33880 (Observable Timing Discrepancy in aaugustin websockets library); CVE-2018-1000518 (aaugustin websockets version 4 contains a CWE-409: Improper Handling of Highly C) +1 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
91% confidence
Finding
websockets has known DoS-related advisories, and the requirement is not pinned, so the deployed version cannot be verified from the manifest. Given this skill's heavy reliance on persistent real-time WebSocket sessions, unresolved version ambiguity increases exposure to availability issues.

Unpinned Dependencies

Low
Category
Supply Chain
Content
twilio>=9.0.0
audioop-lts>=0.2.0
websockets>=16.0
python-multipart>=0.0.20
Confidence
98% confidence
Finding
python-multipart is unpinned despite being a package with a history of parser-related advisories. In a FastAPI app, leaving it unconstrained makes it difficult to verify whether deployments are protected from multipart parsing flaws and DoS issues.

Unverifiable Dependency: python-multipart has 16 known advisory(ies) (CVE-2024-24762 (python-multipart vulnerable to Content-Type Header ReDoS); CVE-2024-53981 (Denial of service (DoS) via deformation `multipart/form-data` boundary); CVE-2026-53539 (python-multipart: Quadratic-time querystring parsing with semicolon separators c) +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
94% confidence
Finding
python-multipart has numerous parser and DoS advisories, and the dependency is unpinned, so there is meaningful uncertainty about whether a vulnerable version may be installed. In a web service context, multipart parser flaws can be exploited remotely to degrade availability or trigger excessive resource consumption.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Content
config.echo_decay_ms = args.echo_decay_ms
    
    logging.basicConfig(
        level=getattr(logging, config.log_level.upper()),
        format="%(asctime)s [%(name)s] %(levelname)s: %(message)s",
    )
Confidence
50% confidence
Finding
Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Static analysis

No suspicious patterns detected.