Back to skill

Security audit

Sen Dev Patterns

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly looks like a personal development pattern library, but it also ships under-disclosed publishing scripts that can find repository credentials, push code, and persist access tokens in Git remotes.

Review this skill before installing or running any bundled scripts. The reference documents and module initializer are mostly ordinary development aids, but do not run publish_skill.py or publish_gitee.py unless you understand that they may use repository credentials, create public repositories, push local code, and store tokens in .git/config. If these scripts were already run, inspect git remote URLs for embedded credentials and rotate affected GitHub or Gitee tokens.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (4)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
publish_skill.py:28
Finding

Publisher Automatically Extracts GitHub Credentials from External Credential Stores

Content
View full analysis

Vulnerability Details

File Location: publish_skill.py, lines 28–66
Vulnerability Type: Credential discovery beyond the minimum privileges required for publishing
Risk Level: High

Vulnerable Code

python
def find_github_token():
    """查找GitHub token"""
    # 1. 环境变量
    for var in ['GITHUB_TOKEN', 'GH_TOKEN', 'GITHUB_PERSONAL_ACCESS_TOKEN']:
        token = os.getenv(var)
        if token:
            print(f"[+] Found token in env: {var[:10]}...")
            return token

    # 2. VSCode扩展
    paths = [
        os.path.expandvars(r"%APPDATA%\Code\User\globalStorage\github-auth-token"),
    ]
    for path in paths:
        if os.path.exists(path):
            try:
                with open(path, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    token = data.get('token') or data.get('github_token')
                    if token:
                        print(f"[+] Found token in VSCode state")
                        return token
            except Exception as e:
                print(f"[!] Error reading {path}: {e}")

    # 3. Git credential
    try:
        result = subprocess.run(
            ['git', 'credential', 'fill'],
            input='protocol=https\nhost=github.com\n\n',
            capture_output=True, text=True, encoding='utf-8',
            timeout=5
        )
        for line in result.stdout.split('\n'):
            if line.startswith('password='):
                return line[9:]
    except:
        pass

    return None

Technical Analysis

Publishing a repository legitimately requires authentication, but the script does not restrict itself to a credential explicitly supplied for the current operation. If no supported environment variable is present, it directly reads a VS Code extension storage location and invokes git credential fill to recover a stored GitHub password or token.

...[truncated 1885 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove all direct reads of VS Code extension storage.
  2. Do not manually invoke and parse git credential fill inside the publisher.
  3. Accept only credentials explicitly selected for the current operation, such as:
    • A fine-grained token supplied through a documented environment variable.
    • GitHub CLI authentication through gh.
    • SSH authentication.
    • Git Credential Manager used transparently by Git.
  4. Require explicit confirmation of the authenticated account, repository owner, repository visibility, and destination before creating or pushing a repository.
  5. Recommend a fine-grained, short-lived token limited to the single target repository and only the required content permissions.
  6. Avoid recommending classic repo scope unless no narrower method is available.
  7. Do not log token values or include credentials in exception messages.
  8. Rotate any credential previously discovered and persisted by this implementation.

T09 · Insecure Skill Coding Practices

Error
Location
publish_skill.py:137
Finding

GitHub Access Token Is Persisted in a Plaintext Git Remote URL

Content
View full analysis

Vulnerability Details

File Location: publish_skill.py, lines 137–145
Vulnerability Type: Plaintext credential storage and command-line exposure
Risk Level: High

Vulnerable Code

python
remote_url = f'https://{username}:{token}@github.com/{username}/{REPO_NAME}.git'

# 添加远程(更新如果存在)
result = subprocess.run(['git', 'remote', 'get-url', 'origin'], capture_output=True, text=True)
if result.returncode == 0:
    subprocess.run(['git', 'remote', 'set-url', 'origin', remote_url], check=True)
    print(f"[*] Updated origin URL")
else:
    subprocess.run(['git', 'remote', 'add', 'origin', remote_url], check=True)
    print(f"[*] Added origin URL")

Technical Analysis

The script interpolates the GitHub username and access token into an HTTPS URL and configures that URL as the repository’s persistent origin remote. Git normally writes remote URLs into .git/config, so the token remains stored in plaintext after the publishing process ends.

The token is also included in the argument list passed to the git subprocess. Depending on the operating system and process-monitoring controls, command-line arguments may be visible to other local processes, administrative monitoring tools, diagnostics, or audit logs.

Credential-bearing remote URLs may additionally be exposed through commands such as git remote -v, repository backups, support archives, accidental copies of the .git directory, or tools that inspect repository configuration.

Attack Path

  1. The user provides a token or the script extracts one from another credential source.
  2. The script constructs an HTTPS URL containing the plaintext token.
  3. The credential-bearing URL is passed as a command-line argument to git remote add or git remote set-url.
  4. Git stores the URL in .git/config.
  5. A local user, process, backup system, diagnostic collector, or accidentally shared repository copy obtains the configuration.
  6. Th ...[truncated 565 chars]
Remediation
View remediation

Remediation Suggestions

  1. Store a credential-free remote URL:

    python
    remote_url = f'https://github.com/{username}/{REPO_NAME}.git'
    
  2. Let Git Credential Manager, GitHub CLI, SSH, or another approved credential helper handle authentication.

  3. If ephemeral token authentication is unavoidable, use a temporary GIT_ASKPASS helper or equivalent mechanism that does not modify the persistent remote.

  4. Do not place tokens in subprocess argument lists, repository configuration, logs, or error messages.

  5. After a push, verify that git remote get-url origin contains no embedded credentials.

  6. For repositories already processed:

    • Replace the remote with a credential-free URL.
    • Revoke and rotate the exposed token.
    • Check local logs, backups, and support bundles for copies.
  7. Add an automated test that rejects remote URLs containing user information or token-like values.

T09 · Insecure Skill Coding Practices

Error
Location
publish_gitee.py:75
Finding

Gitee Access Token Is Persisted in a Plaintext Git Remote URL

Content
View full analysis

Vulnerability Details

File Location: publish_gitee.py, lines 75–81
Vulnerability Type: Plaintext credential storage and command-line exposure
Risk Level: High

Vulnerable Code

python
remote_url = f'https://the13ai:{token}@gitee.com/the13ai/{REPO_NAME}.git'

result = subprocess.run(['git', 'remote', 'get-url', 'gitee'], capture_output=True, text=True)
if result.returncode == 0:
    subprocess.run(['git', 'remote', 'set-url', 'gitee', remote_url], check=True)
else:
    subprocess.run(['git', 'remote', 'add', 'gitee', remote_url], check=True)

Technical Analysis

The Gitee publisher embeds GITEE_TOKEN directly into the remote URL. The URL is persisted by Git in .git/config, leaving the access token readable in plaintext after the publication completes.

The URL is also included in the subprocess arguments used to configure the remote. The use of TLS protects the token while it is transmitted to Gitee, but it does not mitigate local exposure through process inspection, repository configuration, backups, diagnostics, or accidental disclosure of the .git directory.

Authentication is necessary for publishing, but persistent plaintext token storage is not. The implementation therefore exceeds the minimum exposure necessary for the operation.

Attack Path

  1. The user creates a Gitee token with the documented projects permission.
  2. The user stores it in GITEE_TOKEN and runs publish_gitee.py.
  3. The script sends the token to the official Gitee API to check or create the repository.
  4. It constructs a Git remote URL containing the same token.
  5. Git writes the URL into .git/config.
  6. Another local process, user, backup recipient, or diagnostic collector reads the configuration.
  7. The extracted token is reused against Gitee within its granted permissions.

Impact Assessment

An attacker who obtains the token can perform Gitee operations permitted by its scope and t ...[truncated 255 chars]

Remediation
View remediation

Remediation Suggestions

  1. Configure a credential-free remote:

    python
    remote_url = f'https://gitee.com/the13ai/{REPO_NAME}.git'
    
  2. Use SSH or a Gitee-compatible credential manager for Git authentication.

  3. Do not include access tokens in subprocess arguments or persistent Git configuration.

  4. Use a narrowly scoped, expiring token for API repository creation.

  5. Separate API authentication from Git push authentication where possible.

  6. Sanitize existing remotes with git remote set-url and then revoke the previously embedded token.

  7. Review backups, logs, and shared repository copies that may contain the old .git/config.

  8. Add validation that rejects URLs containing credentials before calling git remote add or git remote set-url.

T09 · Insecure Skill Coding Practices

Warning
Location
PUBLISH_GUIDE.md:29
Finding

Publishing Documentation Directs Users to an Insecure Token-Persisting Workflow

Content
View full analysis

Vulnerability Details

File Locations: PUBLISH_GUIDE.md, lines 29–45; GITEE_SETUP.md, lines 5–13
Vulnerability Type: Unsafe credential-handling guidance
Risk Level: Medium

Vulnerable Documentation

PUBLISH_GUIDE.md:

markdown
## 国内分发方案

### Gitee(码云)- 国内可直接访问

```bash
# 方式1: 使用脚本
python publish_gitee.py

# 方式2: 手动
git remote add gitee https://gitee.com/the13ai/sen-dev-patterns.git
git push -u gitee master

Gitee Token 获取:

  1. 访问 https://gitee.com/oauth/applications
  2. 创建应用,勾选 projects 权限
  3. 获取 Access Token
  4. 设置: set GITEE_TOKEN=your_token
text

`GITEE_SETUP.md`:

```markdown
- [ ] 在 Gitee 创建应用获取 Token
  - 地址: https://gitee.com/oauth/applications
  - 权限: projects

- [ ] 运行发布脚本
  ```bash
  cd C:\Users\sen\.codebuddy\skills\sen-dev-patterns
  set GITEE_TOKEN=your_token
  python publish_gitee.py
  ```

Technical Analysis

The documentation explicitly instructs users to create a Gitee token and execute publish_gitee.py. That script stores the token in a plaintext Git remote URL. The documentation does not disclose this behavior, warn users about persistent credential exposure, or recommend secure authentication alternatives.

Although setting a token in an environment variable is not inherently unsafe, the documented follow-up command invokes code that moves the token into persistent repository configuration. Consequently, the documentation makes the insecure path an expected usage flow rather than an obscure implementation detail.

The guide also recommends the broad projects permission without discussing expiration, account limitations, or whether a narrower scope is available.

Attack Path

  1. A user follows GITEE_SETUP.md or PUBLISH_GUIDE.md.
  2. The user creates a Gitee access token with project permissions.
  3. The user sets GITEE_TOKEN.
  4. The user runs publish_gitee.py as instructed.
  5. The script embeds the token ...[truncated 705 chars]
Remediation
View remediation

Remediation Suggestions

  1. Replace the documented script flow with SSH or a credential-manager-based workflow.
  2. Explain that tokens must never be placed in Git remote URLs.
  3. Document the minimum required token permissions and recommend expiration.
  4. Require users to verify that git remote -v contains no credentials after publication.
  5. Add immediate token-revocation guidance for users who previously ran the affected script.
  6. Clearly distinguish API authentication used to create a repository from Git authentication used to push content.
  7. Keep the existing manual credential-free remote commands as the preferred workflow.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (49)

Tainted flow: 'token' from os.getenv (line 30, credential/environment) → requests.get (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 · publish_gitee.py (reported line 49)May include surrounding context.

python
return

    # 检查仓库是否存在
    resp = requests.get(f'{GITEE_API}/repos/the13ai/{REPO_NAME}', params={'access_token': token})
    if resp.status_code == 200:
        print(f"[*] Gitee仓库已存在: {REPO_NAME}")
    else:

Tainted flow: 'data' from os.getenv (line 54, credential/environment) → requests.post (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 · publish_gitee.py (reported line 63)May include surrounding context.

python
'has_issues': True,
            'has_wiki': True
        }
        resp = requests.post(f'{GITEE_API}/user/repos', data=data)
        if resp.status_code == 201:
            print(f"[+] Gitee仓库创建成功: {REPO_NAME}")
        else:

Tainted flow: 'data' from os.getenv (line 169, credential/environment) → requests.post (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 · publish_skill.py (reported line 89)May include surrounding context.

python
return True

    # 创建
    resp = requests.post(f'{GITHUB_API}/user/repos', headers=headers, json=data)
    if resp.status_code == 201:
        print(f"[+] GitHub repo created: {repo_name}")
        return True

Tainted flow: 'data' from os.getenv (line 169, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

This request sends the Gitee access token in the POST body, increasing exposure risk through logs, proxies, debugging middleware, or error captures compared with header-based authentication. In addition, the skill's stated purpose does not justify transmitting repository-creation credentials to an external service.

Content

Scanner excerpt · publish_skill.py (reported line 177)May include surrounding context.

python
'auto_init': False
    }

    resp = requests.post(f'{GITEE_API}/user/repos', data=data)
    if resp.status_code == 201 or 'already exists' in resp.text.lower():
        print(f"[+] Gitee repo ready: gitee.com/sinadook/{repo_name}")
        return True

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

声明描述强调的是知识沉淀内容本身及其复用场景,相当于一个开发规范/经验库的用途说明;而实际代码并不实现这些内容管理、检索、复用或规范调用能力。它的主要功能是自动发布到Gitee,包括鉴权、远程仓库存在性检查、仓库创建、配置git remote以及执行git push。这属于部署/发布自动化能力,且涉及外部网络、仓库写入和凭证使用,这些都未在声明中体现。因此描述与实际行为存在明显且实质性的不匹配。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description presents the skill as a repository of personal development patterns and reusable experience (layouts, styles, modules, algorithms, pitfalls). The supplied code does not implement retrieval, organization, or reuse of such development knowledge. Instead, it is an automated publication script for GitHub/Gitee. It accesses sensitive resources by searching for GitHub tokens in environment variables, VSCode global storage, and git credentials, then uses those credentials to create repositories and push code. These are significant undeclared capabilities and represent a materially different primary purpose from the declared skill description.

Content

No source excerpt is available for this finding.

Lp1

High
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The script performs external network operations against Gitee APIs and pushes code remotely, but this capability is not aligned with the declared personal development-patterns purpose. Hidden or undeclared outbound connectivity increases supply-chain and data-transfer risk because users may not expect repository creation and remote publication behavior.

Content

No source excerpt is available for this finding.

Lp1

High
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The script performs external network operations against Gitee APIs and pushes code remotely, but this capability is not aligned with the declared personal development-patterns purpose. Hidden or undeclared outbound connectivity increases supply-chain and data-transfer risk because users may not expect repository creation and remote publication behavior.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

This file's behavior materially differs from the skill's stated purpose of reusing personal development patterns and knowledge: it creates a remote repository and pushes local code to Gitee. Such scope mismatch is dangerous because users may install or trust the skill for documentation/code reuse while it contains publication automation with credential use and data egress.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

Repository creation, network access, and git subprocess execution are not justified by the described function of a personal development patterns asset. In a mismatched skill context, these capabilities increase the chance of unexpected code publication, credential use, and outbound transfer of local repository contents.

Content

No source excerpt is available for this finding.

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 · PUBLISH_GUIDE.md (reported line 44)May include surrounding context.

md
print("1. 访问 https://gitee.com/oauth/applications")
        print("2. 点击 '创建应用'")
        print("3. 填写应用信息,勾选 'projects' 权限")
        print("4. 获取 Access Token")
        print("5. 设置环境变量: set GITEE_TOKEN=your_token")
        print("6. 重新运行此脚本")
        print("\n或者手动创建仓库:")

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 · publish_gitee.py (reported line 37)May include surrounding context.

python
print("1. 访问 https://gitee.com/oauth/applications")
        print("2. 点击 '创建应用'")
        print("3. 填写应用信息,勾选 'projects' 权限")
        print("4. 获取 Access Token")
        print("5. 设置环境变量: set GITEE_TOKEN=your_token")
        print("6. 重新运行此脚本")
        print("\n或者手动创建仓库:")

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 · publish_skill.py (reported line 112)May include surrounding context.

python
print("1. 访问 https://gitee.com/oauth/applications")
        print("2. 点击 '创建应用'")
        print("3. 填写应用信息,勾选 'projects' 权限")
        print("4. 获取 Access Token")
        print("5. 设置环境变量: set GITEE_TOKEN=your_token")
        print("6. 重新运行此脚本")
        print("\n或者手动创建仓库:")

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The script searches multiple local secret sources—environment variables, VSCode storage, and Git credential helpers—to obtain a GitHub token without a strong functional need tied to the advertised skill. This broad credential discovery behavior resembles secret harvesting and materially increases risk in developer environments.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The script accesses sensitive token sources silently and without an explicit warning that it will inspect local environment variables, editor state, and Git credential storage. Lack of informed consent around secret access is especially risky in a skill whose advertised purpose does not imply credential handling.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

This script performs authenticated network operations, creates remote repositories, modifies Git remotes, and pushes code, none of which are justified by a pattern-library skill description. In-context, the mismatch makes the behavior more dangerous because it can surprise users and cause unreviewed code or credential exposure.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill claims to help reuse personal development patterns, but this file performs repository creation and code publication to external platforms. That mismatch is dangerous because users invoking a seemingly local productivity skill may unknowingly trigger credential use and outbound code transfer.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

Embedding the GitHub token directly into the remote URL and writing it into repository configuration creates durable credential exposure with no warning to the user. This can leak secrets to local files, diagnostics, screenshots, backups, and any tool that enumerates Git remotes.

Content

No source excerpt is available for this finding.

Context Leakage

High
Category
Data Exfiltration
Confidence
85% confidence
Finding

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

Content

Scanner excerpt · references/code-modules.md (reported line 678)May include surrounding context.

python
def create_progress_dialog(parent, title="处理中", max_steps=100):
    """创建进度对话框"""
    from PySide6.QtWidgets import QProgressDialog
    
    dialog = QProgressDialog(title, "取消", 0, max_steps, parent)
    dialog.setWindowTitle(title)

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest description and title/content are primarily presented in Chinese, framing the skill as a Chinese-language experience, while no instruction offers users a language/locale choice. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless clearly justified as region-specific, which is not documented here.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

The script rewrites the git remote to include the access token directly in the URL without warning the user that this stores credentials in local git configuration. This can leak the token through config inspection, local filesystem access, debugging output, accidental screenshots, or tool integrations, resulting in credential compromise.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · publish_gitee.py (reported line 77)May include surrounding context.

python
remote_url = f'https://the13ai:{token}@gitee.com/the13ai/{REPO_NAME}.git'

    result = subprocess.run(['git', 'remote', 'get-url', 'gitee'], capture_output=True, text=True)
    if result.returncode == 0:
        subprocess.run(['git', 'remote', 'set-url', 'gitee', remote_url], check=True)
    else:

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · publish_gitee.py (reported line 79)May include surrounding context.

python
result = subprocess.run(['git', 'remote', 'get-url', 'gitee'], capture_output=True, text=True)
    if result.returncode == 0:
        subprocess.run(['git', 'remote', 'set-url', 'gitee', remote_url], check=True)
    else:
        subprocess.run(['git', 'remote', 'add', 'gitee', remote_url], check=True)

Tainted flow: 'remote_url' from os.getenv (line 75, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Confidence
98% confidence
Finding

The script builds a git remote URL that embeds the Gitee access token, then writes it into local git configuration via git remote set-url. This can expose the token to other local users, tooling, logs, shell history, backup systems, or accidental disclosure when inspecting git remotes, enabling unauthorized repository access.

Content

Scanner excerpt · publish_gitee.py (reported line 79)May include surrounding context.

python
result = subprocess.run(['git', 'remote', 'get-url', 'gitee'], capture_output=True, text=True)
    if result.returncode == 0:
        subprocess.run(['git', 'remote', 'set-url', 'gitee', remote_url], check=True)
    else:
        subprocess.run(['git', 'remote', 'add', 'gitee', remote_url], check=True)

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · publish_gitee.py (reported line 81)May include surrounding context.

python
if result.returncode == 0:
        subprocess.run(['git', 'remote', 'set-url', 'gitee', remote_url], check=True)
    else:
        subprocess.run(['git', 'remote', 'add', 'gitee', remote_url], check=True)

    result = subprocess.run(['git', 'push', '-u', 'gitee', 'master'], capture_output=True, text=True)
    if result.returncode == 0: