Back to skill

Security audit

C# LSP

Security checks for vulnerabilities and agentic risk

Overview

This skill is a C# code-navigation helper, but its installer and runtime grant broader and more persistent local authority than the C# description makes clear.

Review before installing. Prefer not to run the bundled setup script as-is on a shared or privileged machine. If you proceed, avoid SUDO_PASS, inspect any existing /usr/local/bin/lsp-query before linking, prefer a user-local bin path, restrict LSP_SERVER/LSP_LANG use, and treat queried files as being shared with local language-server subprocesses.

Vulnerability Patterns
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • 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
Findings (5)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/lsp-query.py:153
Finding
Undocumented Language-Server Command Override Enables Arbitrary Process Execution<![CDATA[ ## Vulnerability Details **File Location**: `scripts/lsp-query.py:153-160, 235-242` **Vulnerability Type**: Unrestricted executable override and functionality exceeding declared scope **Risk Level**: Medium ### Vulnerable Code ```python def get_server_cmd(lang): """Get the server command for a language, checking if the binary exists.""" override = os.environ.get("LSP_SERVER") if override: return override.split() cfg = LANGUAGES.get(lang) if not cfg: return None ``` The resulting command is executed directly: ```python def start(self): self._proc = subprocess.Popen( self.server_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, ) ``` ### Technical Analysis The Skill is presented as a C#-specific integration using the fixed `csharp-ls` server. However, the implementation supports numerous additional language servers and permits the server command to be replaced through the `LSP_SERVER` environment variable. Although `subprocess.Popen` is invoked without `shell=True`, the first element of the environment-controlled command is still executed as a program. There is no allowlist, trusted executable directory, ownership verification, or check that the override is actually an LSP server. This capability materially exceeds the declared C#-only behavior. It can turn an ordinary LSP query into an execution trigger if an attacker can influence the daemon's startup environment, wrapper configuration, or inherited environment variables. ### Attack Path 1. An attacker gains the ability to influence environment variables used by the agent, automation runner, shell profile, or process that invokes `lsp-query`. 2. The attacker sets `LSP_SERVER` to an attacker-controlled executable and optional arguments. 3. The user or agent performs an ordinary LSP query. 4. The daemon calls `get_server_cmd()` and accepts the override without validation. 5. `subprocess.Pope ...[truncated 541 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `LSP_SERVER` if arbitrary server replacement is unnecessary. 2. Restrict the Skill to `csharp-ls` to match its declared functionality. 3. If overrides are required, accept only commands from an explicit executable allowlist. 4. Resolve the server to a trusted absolute path rather than relying on `PATH`. 5. Verify that the executable is a regular file, is not symlinked to an untrusted location, and is not writable by untrusted users. 6. Do not inherit security-sensitive server configuration from uncontrolled shell profiles or agent-provided environments. 7. Document every supported language and executable override capability in `SKILL.md`. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/lsp-query.py:714
Finding
Unauthenticated Unix Socket Accepts Privileged Daemon Requests<![CDATA[ ## Vulnerability Details **File Location**: `scripts/lsp-query.py:714-729, 760-773` **Vulnerability Type**: Missing local authorization and insufficient socket permission hardening **Risk Level**: Medium ### Vulnerable Code ```python def _run_daemon(): """Run the multi-language LSP daemon.""" sock_path = _sock_path() os.makedirs(os.path.dirname(sock_path), exist_ok=True) if os.path.exists(sock_path): os.unlink(sock_path) workspace = _workspace_root() daemon = MultiLangDaemon(workspace) server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) server.bind(sock_path) server.listen(5) server.settimeout(1.0) ``` Requests are parsed and executed without authenticating the peer: ```python last_activity = time.time() try: data = b"" while True: chunk = conn.recv(65536) if not chunk: break data += chunk if b"\n\n" in data: break request = json.loads(data.decode("utf-8").strip()) result = _handle_request(daemon, request) response = json.dumps(result).encode("utf-8") conn.sendall(response) ``` ### Technical Analysis The daemon exposes commands through a Unix-domain socket but performs no peer-credential check, token authentication, or request authorization. It also does not explicitly create the parent directory with mode `0700` or set the socket to mode `0600`. Consequently, effective protection depends on the user's existing cache-directory permissions and process `umask`. On a multi-user system where another account can traverse the directory and connect to the socket, that account can submit commands under the victim daemon's security context. The request handler supports server startup, arbitrary supplied file paths, source-file processing, server enumer ...[truncated 1184 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create `~/.cache/lsp-query` with mode `0700` and verify its ownership before use. 2. Set a restrictive `umask`, such as `0o077`, before creating the socket and PID file. 3. Explicitly set the socket mode to `0600` after binding. 4. Reject a socket directory, socket path, or PID path that is a symbolic link or owned by another user. 5. Authenticate clients using Unix peer credentials and require the peer UID to match the daemon UID. 6. Restrict requested file paths to canonical paths beneath the configured workspace. 7. Apply a maximum request size and reject oversized or malformed payloads before unbounded accumulation in memory. 8. Add tests covering cross-user access, socket permissions, symlink handling, and out-of-workspace file requests. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/lsp-query.py:275
Finding
Unconditional Logging to a Predictable Shared Temporary File Permits Symlink Attacks<![CDATA[ ## Vulnerability Details **File Location**: `scripts/lsp-query.py:275-292` **Vulnerability Type**: Unsafe temporary-file handling and unintended path disclosure **Risk Level**: Medium ### Vulnerable Code ```python def _handle_server_request(self, msg): """Respond to server-to-client requests (e.g. client/registerCapability).""" rid = msg["id"] method = msg.get("method", "") with open("/tmp/lsp-query-debug.log", "a") as _dbg: _dbg.write(f"[srv-req] {method} id={rid}\n") response = {"jsonrpc": "2.0", "id": rid, "result": None} try: data = encode_msg(response) with self._lock: self._proc.stdin.write(data) self._proc.stdin.flush() except Exception as e: with open("/tmp/lsp-query-debug.log", "a") as _dbg: _dbg.write(f"[srv-req-err] {method}: {e}\n") def _handle_notification(self, msg): method = msg.get("method", "") with open("/tmp/lsp-query-debug.log", "a") as _dbg: _dbg.write(f"[notif] {method}\n") if method == "textDocument/publishDiagnostics": _dbg.write(f" uri={msg.get('params',{}).get('uri','')}\n") ``` ### Technical Analysis The daemon opens a predictable path in the shared `/tmp` directory using ordinary append mode. This follows symbolic links and does not verify ownership, file type, link count, or permissions. An attacker can pre-create `/tmp/lsp-query-debug.log` as a symbolic link to another file writable by the victim. When the victim runs an LSP query, the daemon follows the link and appends log content to the target. Logging is also unconditional. The documentation states that logging occurs only when `LSP_DEBUG=1`, but the code never checks that variable. Diagnostic notifications write file URIs, disclosing workspace and source-file paths to the log. ### Attack Path 1. The predictable log file does not yet exist. 2. A l ...[truncated 882 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not write logs unless `LSP_DEBUG=1` has been explicitly enabled. 2. Store logs under the private `~/.cache/lsp-query` directory rather than `/tmp`. 3. Create the log with mode `0600`. 4. Open it using secure flags such as `O_NOFOLLOW`, `O_CREAT`, and `O_APPEND`, then verify with `fstat()` that it is a regular file owned by the current user. 5. Refuse to use an existing log with unexpected ownership or multiple hard links. 6. Avoid recording full source paths unless necessary; redact workspace-specific path components. 7. Correct the documentation so it accurately reflects actual logging behavior. 8. Add a regression test that pre-creates the log path as a symbolic link and verifies that the daemon refuses it. ]]>

T07 · Tool Hijacking and Spoofing

Error
Location
scripts/setup.sh:124
Finding
Forced System-Wide Symlink Replacement Enables Tool Hijacking<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup.sh:124-140` **Vulnerability Type**: Global command replacement and mutable executable target **Risk Level**: High ### Vulnerable Code ```bash chmod +x "$LSP_QUERY" 2>/dev/null || true if [ -L "$SYMLINK_PATH" ] && [ "$(readlink -f "$SYMLINK_PATH")" = "$(readlink -f "$LSP_QUERY")" ]; then skip "$SYMLINK_PATH → $LSP_QUERY" elif [ -w "$(dirname "$SYMLINK_PATH")" ] 2>/dev/null; then ln -sf "$LSP_QUERY" "$SYMLINK_PATH" ok "$SYMLINK_PATH → $LSP_QUERY" else # sudo 필요 if command -v sudo &>/dev/null; then info "심볼릭 링크 생성에 sudo가 필요합니다..." if [ -n "${SUDO_PASS:-}" ]; then echo "$SUDO_PASS" | sudo -S ln -sf "$LSP_QUERY" "$SYMLINK_PATH" 2>/dev/null ok "$SYMLINK_PATH → $LSP_QUERY (sudo)" elif sudo -n true 2>/dev/null; then sudo ln -sf "$LSP_QUERY" "$SYMLINK_PATH" ok "$SYMLINK_PATH → $LSP_QUERY (sudo)" ``` ### Technical Analysis The setup process uses `ln -sf` to create `/usr/local/bin/lsp-query`. The force option replaces an existing destination without first proving that the existing command belongs to this Skill. The privileged global command is a symbolic link to the script inside the current Skill or Git working directory, rather than an immutable root-owned installed copy. Project documentation explicitly describes edits and branch switches in that working tree as immediately changing the command's behavior. This creates two related risks: - An unrelated existing `/usr/local/bin/lsp-query` can be overwritten. - Anyone who can later modify the linked working-tree script can change what users execute through a trusted-looking global command without repeating the privileged setup step. ### Attack Path 1. A user runs `setup.sh`, potentially authorizing the operation through `sudo`. 2. The script force-replaces `/usr/local/bin/lsp-query`. 3. The resulting global command points to a mutable repository script. ...[truncated 925 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Default to a user-local installation such as `~/.local/bin/lsp-query`. 2. Never force-replace an unrelated file in `/usr/local/bin`. 3. If the destination exists, verify that it is already a link installed by this Skill; otherwise stop and request explicit user action. 4. For a system-wide installation, copy a reviewed release artifact into a root-owned directory rather than linking to a mutable working tree. 5. Make the installed file root-owned and not writable by ordinary users. 6. Use versioned installation directories and update the active link only after integrity verification. 7. Verify release hashes or signatures before installing updates. 8. Add tests for destination collisions, mutable target permissions, and ownership validation. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/setup.sh:133
Finding
Sudo Password Is Accepted Through an Environment Variable and Pipeline<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup.sh:133-137` **Vulnerability Type**: Insecure privileged credential handling **Risk Level**: Medium ### Vulnerable Code ```bash if command -v sudo &>/dev/null; then info "심볼릭 링크 생성에 sudo가 필요합니다..." if [ -n "${SUDO_PASS:-}" ]; then echo "$SUDO_PASS" | sudo -S ln -sf "$LSP_QUERY" "$SYMLINK_PATH" 2>/dev/null ok "$SYMLINK_PATH → $LSP_QUERY (sudo)" ``` ### Technical Analysis The setup script supports supplying a sudo password through the `SUDO_PASS` environment variable. Privileged credentials should not be stored in process environments because they can be retained or exposed by parent processes, automation systems, diagnostic tooling, crash capture, shell configuration, and improperly secured logs. The password is passed through a pipeline to `sudo -S`. Although it is not included directly in the command-line argument list, the environment variable remains available to the setup process and any unexpectedly invoked child process that inherits the environment. This password handling is unnecessary for the Skill's legitimate purpose because `sudo` can prompt interactively, and the command can instead be shown for explicit manual execution. ### Attack Path 1. A user or CI system exports `SUDO_PASS` before running setup. 2. The setup process inherits the plaintext password in its environment. 3. A compromised parent process, diagnostic collector, shell wrapper, or other component with access to that environment captures the value. 4. The attacker obtains the victim's sudo password. 5. The attacker reuses the password to execute unrelated privileged commands where sudo policy permits. ### Impact Assessment Disclosure may allow privilege escalation to root or another privileged account, depending on the victim's sudo policy and password reuse. The affected scope is not limited to `lsp-query`: a stolen sudo password can authorize arbitrary commands permitted by the syste ...[truncated 27 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove all support for `SUDO_PASS`. 2. Allow `sudo` to prompt through its normal interactive terminal mechanism. 3. Prefer a user-local installation that requires no elevated privileges. 4. If system-wide installation is optional, print the exact privileged command and let the user execute it separately. 5. Explicitly unset sensitive environment variables before launching any child process. 6. Document that passwords and tokens must never be supplied through environment variables used by the setup script. 7. Add automated checks that fail if password variables or `sudo -S` credential pipelines are introduced. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (39)

Tainted flow: 'response' from os.environ.get (line 774, credential/environment) → socket.socket.sendall (network output)

Critical
Category
Data Flow
Content
request = json.loads(data.decode("utf-8").strip())
                result = _handle_request(daemon, request)
                response = json.dumps(result).encode("utf-8")
                conn.sendall(response)
            except Exception as e:
                try:
                    conn.sendall(json.dumps({"error": str(e)}).encode("utf-8"))
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill is described as providing code intelligence, but the setup flow performs privileged or persistent system modifications such as global dotnet tool installation, shell profile edits, symlink creation, and local cache setup. That is dangerous because these side effects change the host environment beyond the expected scope of a language-assistance skill and can create persistence, PATH hijacking risk, or unintended system-wide impact if users run the setup without understanding the consequences.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The skill is described as providing code intelligence, but the setup flow performs privileged or persistent system modifications such as global dotnet tool installation, shell profile edits, symlink creation, and local cache setup. That is dangerous because these side effects change the host environment beyond the expected scope of a language-assistance skill and can create persistence, PATH hijacking risk, or unintended system-wide impact if users run the setup without understanding the consequences.

YARA rule 'backdoor_persistence': Backdoor persistence with malicious payloads (shell commands, SSH key injection, hidden root users) [malware]

High
Category
YARA Match
Content
First query is very slow (30–60 seconds)

**Normal behavior.** Roslyn needs to load the entire solution and build the type system on first use. Subsequent queries are ~200ms.

For large solutions (100+ projects), initial load can take up to 60 seconds.

### "csharp-ls: command not found"

**Cause**: `~/.dotnet/tools` not in PATH.

```bash
export PATH="$HOME/.dotnet/tools:$PATH"

# Permanent fix
echo 'export PATH="$HOME/.dotnet/tools:$PATH"' >> ~/.bashrc
```

Or re-run setup:
```bash
bash scripts/setup.sh
```

### Stale daemon (old code still running)

**Cause**: Daemon was started before code changes and is still running the old version.

```bash
# Kill daemon
lsp-query shutdown

# Clean up
rm -f ~/.cache/lsp-query/daemon.sock ~/.cache/lsp-query/daemon.sock.pid

# Next lsp-query call will start fresh daemon
```

### "dotnet tool install fails with DotnetToolSettings.xml"

**Cause**: Some csharp-ls versions have packaging issues.

```bash
# Pin to known-good version
dotnet tool instal
Confidence
75% confidence
Finding
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The implementation materially differs from the manifest: it is a multi-language LSP daemon rather than a narrowly scoped C# helper. This mismatch is security-relevant because reviewers and users may grant trust based on a C#-only description while the code actually enables broader file access and process execution across many ecosystems.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
The skill exposes analysis capability for many languages unrelated to its declared C# purpose. In agent environments, unnecessary capability expansion increases attack surface, broadens the set of files that may be opened and transmitted to subprocesses, and makes policy enforcement harder.

Chaining Abuse

High
Category
Tool Misuse
Content
if command -v sudo &>/dev/null; then
        info "심볼릭 링크 생성에 sudo가 필요합니다..."
        if [ -n "${SUDO_PASS:-}" ]; then
            echo "$SUDO_PASS" | sudo -S ln -sf "$LSP_QUERY" "$SYMLINK_PATH" 2>/dev/null
            ok "$SYMLINK_PATH → $LSP_QUERY (sudo)"
        elif sudo -n true 2>/dev/null; then
            sudo ln -sf "$LSP_QUERY" "$SYMLINK_PATH"
Confidence
98% confidence
Finding
Piping an environment-sourced secret into sudo chains together plaintext secret handling and privileged execution. In an agent skill context, where scripts may run in automated environments with logs and inherited environment state, this is more dangerous than in a purely local interactive installer because it normalizes unattended privilege escalation.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
info "LSP 쿼리 테스트 (첫 실행은 30초+ 소요)..."
    lsp-query shutdown 2>/dev/null || true
    rm -f "$CACHE_DIR/daemon.sock" "$CACHE_DIR/daemon.sock.pid"

    RESULT=$(LSP_WORKSPACE="$TEST_DIR/Verify" lsp-query hover "$TEST_DIR/Verify/Program.cs" 4 16 2>&1)
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
export LSP_WORKSPACE=/tmp/test/Mini
        lsp-query shutdown 2>/dev/null || true
        rm -f ~/.cache/lsp-query/daemon.sock ~/.cache/lsp-query/daemon.sock.pid

        # ═══ TEST 3: Hover ═══
        echo "TEST:hover:START"
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
export LSP_WORKSPACE=/tmp/test/Mini
        lsp-query shutdown 2>/dev/null || true
        rm -f ~/.cache/lsp-query/daemon.sock ~/.cache/lsp-query/daemon.sock.pid

        # ═══ TEST 3: Hover ═══
        echo "TEST:hover:START"
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
export LSP_WORKSPACE=/tmp/test/Mini
        lsp-query shutdown 2>/dev/null || true
        rm -f ~/.cache/lsp-query/daemon.sock ~/.cache/lsp-query/daemon.sock.pid

        # ═══ TEST 3: Hover ═══
        echo "TEST:hover:START"
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill exposes shell, network, environment, and file read/write capabilities through setup and daemon operations, but it does not declare any explicit tool scope or permissions boundaries. That omission is dangerous because consumers cannot easily assess or restrict what the skill may do, and the setup instructions include actions like global installs and filesystem changes that exceed passive code-intelligence behavior.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
The file's natural-language instructions are presented in Korean throughout, which effectively forces a specific language for operators reading the deployment process. Under the stated policy, a fixed language without user opt-in or a documented locale-specific justification is a policy violation.

Missing User Warnings

Medium
Confidence
79% confidence
Finding
This markdown file includes operational steps that publish code (`git push origin main --tags`) and explicitly states that the pushed code is immediately the deployed version and will be received by other users. Because this behavior can affect system integrity and other users, the document should include a clear user-facing warning about the immediate deployment impact before those commands are run.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The manifest claims use of `csharp-ls`, but the code permits replacing the server command globally via `LSP_SERVER`, allowing execution of arbitrary alternative binaries. That undermines the trust model implied by the manifest and turns a specific language-server dependency into a generic command-execution mechanism.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The server-command resolution logic allows execution of whatever binary is configured for a language, and also supports a global override. For a C#-scoped skill, that is broader than necessary and creates an avoidable local execution primitive with access to workspace content.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
self._diagnostics = {}

    def start(self):
        self._proc = subprocess.Popen(
            self.server_cmd,
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
Confidence
90% confidence
Finding
The code launches a subprocess using `self.server_cmd`, and that command can be influenced indirectly through `LSP_SERVER` or by selecting any configured language server. In the context of an agent skill, this broad process-execution surface enables arbitrary local binaries to run under the agent's privileges, which exceeds the declared C#-only purpose and can be abused for unintended code execution.

Session Persistence

Medium
Category
Rogue Agent
Content
if msg is None:
                break
            # Server-to-client request (has both "method" and "id")
            # e.g. client/registerCapability, window/workDoneProgress/create
            if "method" in msg and "id" in msg:
                self._handle_server_request(msg)
                continue
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.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
When a file is opened, its full contents are read and sent to a background language-server subprocess. In this skill context, that can expose sensitive source code or secrets embedded in files to additional tools/processes without explicit disclosure or minimization, which is more concerning because the skill's scope is broader than advertised.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if ws:
        return ws
    try:
        root = subprocess.check_output(
            ["git", "rev-parse", "--show-toplevel"],
            stderr=subprocess.DEVNULL, text=True
        ).strip()
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The usage banner lists supported languages as python, typescript/js, rust, go, c/c++, bash, java, css, html, and json, but omits C# even though the code includes a csharp entry and the manifest is specifically for C#. This is an active documentation contradiction about the tool's intended and actual language scope.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The file’s comments, usage guidance, and later runtime messages are written in Korean, indicating the skill is designed to communicate in a fixed language. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is explicitly justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
fail ".NET SDK가 설치되어 있지 않습니다."
    info ""
    info "설치 방법:"
    info "  Ubuntu/Debian:  sudo apt install dotnet-sdk-9.0"
    info "  macOS:          brew install dotnet-sdk"
    info "  기타:           https://dot.net/download"
    info ""
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
fail ".NET SDK가 설치되어 있지 않습니다."
    info ""
    info "설치 방법:"
    info "  Ubuntu/Debian:  sudo apt install dotnet-sdk-9.0"
    info "  macOS:          brew install dotnet-sdk"
    info "  기타:           https://dot.net/download"
    info ""
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
fail ".NET SDK가 설치되어 있지 않습니다."
    info ""
    info "설치 방법:"
    info "  Ubuntu/Debian:  sudo apt install dotnet-sdk-9.0"
    info "  macOS:          brew install dotnet-sdk"
    info "  기타:           https://dot.net/download"
    info ""
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Static analysis

No suspicious patterns detected.