Back to skill

Security audit

Dev Factory Repo

Security checks for vulnerabilities and agentic risk

Overview

This skill is an automated code factory with disclosed external integrations, but it gives generated and remotely sourced work too much unsandboxed authority over files, credentials, commands, and GitHub publishing.

Install only in a disposable, sandboxed environment with no personal or production secrets. Use fine-grained test-only GitHub and Notion tokens, set repositories private by default, review all generated files before running tests or publishing, and disable automatic publishing and external model fixing for confidential code.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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 (5)

T01 · Skill Instruction Hijacking

Error
Location
builder/orchestrator.py:81
Finding

Untrusted Notion Records Are Passed to a Bash-Enabled Coding Agent

Content
View full analysis
List[Dict]: """Notion에서 "개발중" 상태인 프로젝트 조회""" if not self.token: return [] try: query_data = { "filter": { "property": "상태", "status": {"equals": "개발중"} } } req = urllib.request.Request( f"{self.api_base}/databases/{self.database_id}/query", data=json.dumps(query_data).encode('utf-8'), headers=self.headers ) with urllib.request.urlopen(req, timeout=10) as response: result = json.loads(response.read().decode()) projects = [] for page in result.get('results', []): projects.append(self._parse_page(page)) return projects except Exception as e: logger.warning("Failed to query Notion: %s", e) return [] def _parse_page(self, page: Dict) -> Dict: """Notion 페이지를 ProjectIdea 형식으로 파싱""" props = page.get('properties', {}) title = "" if '내용' in props and 'title' in props['내용']: titles = props['내용']['title'] if titles: title = titles[0].get('text', {}).get('content', '') description = "" if '도구 설명' in props and 'rich_text' in props['도구 설명']: texts = props['도구 설명']['rich_text'] if texts: description = texts[0].get('text', {}).get('content', '') url = "" if 'URL' in props and 'url' in props['URL']: url = props['URL']['url'] return { 'title': title, 'description': description, 'url': url, 'notion_page_id': page['id'] } ``` ```pytho ...[truncated 4388 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
builder/pipeline.py:170
Finding

Agent-Generated Test Code Executes Unsandboxed with Host Secrets

Content
View full analysis
Dict: """Build -> Test -> Fix""" self.state.set_stage(PipelineStage.BUILDING.value) self.state.current_project = idea['title'] # ProjectIdea로 변환 project = ProjectIdea.from_dict(idea) # 개발 build_result = self.orchestrator.develop(project, project_path) if build_result.success: # 테스트 self.state.set_stage(PipelineStage.TESTING.value) test_result = self._run_tests(project_path) if test_result['success']: self.state.set_stage(PipelineStage.COMPLETED.value) logger.info("Build completed: %s", project.title) else: # 수정 시도 self.state.set_stage(PipelineStage.FIXING.value) error = self.analyzer.analyze(test_result['output']) fixed = self.fixer.fix(error, project_path, project.complexity) if fixed: # 재테스트 test_result = self._run_tests(project_path) build_result.success = test_result['success'] self.state.current_project = None return build_result.to_dict() def _run_tests(self, project_path: Path) -> Dict: """테스트 실행""" import subprocess import os try: result = subprocess.run( ['python3', '-m', 'unittest', 'discover', '-s', 'tests', '-v'], cwd=str(project_path), capture_output=True, text=True, timeout=30, env={**os.environ, 'PYTHONPATH': 'src'} ) return { 'success': result.returncode == 0, 'output': result.stdout + result.stderr } except subprocess.TimeoutExpired: return {'success': False, 'output': 'Test ...[truncated 2314 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
builder/correction/analyzer.py:48
Finding

Traceback-Controlled Path Can Redirect the Automated Fixer Outside the Project

Content
View full analysis
Dict: """테스트 출력에서 에러 타입, 위치, 수정 전략 분석""" error_type = self._detect_type(test_output) file_path, line_number = self._extract_location(test_output) details = self._extract_details(error_type, test_output) return { 'type': error_type, 'raw_output': test_output[:500], 'file_path': file_path, 'line_number': line_number, 'details': details, 'fix_suggestion': self._get_suggestion(error_type, details), } ``` ```python def _extract_location(self, output: str) -> Tuple[Optional[str], Optional[int]]: """에러 위치 추출""" match = re.search(r'File "([^"]+)", line (\d+)', output) if match: return match.group(1), int(match.group(2)) return None, None ``` ```python def fix(self, error: Dict, project_path: Path, complexity: str = "medium") -> bool: error_type = error.get('type', 'unknown') file_path = error.get('file_path') line_number = error.get('line_number') if not file_path: logger.warning("No file path in error, cannot auto-fix") return False file_path = Path(file_path) if not file_path.exists(): logger.warning("File %s not found", file_path) return False if self._fix_by_rules(error, file_path, line_number): return True ``` ```python def _fix_key_error(self, error: Dict, file_path: Path, line_number: Optional[int]) -> bool: """KeyError 수정: dict['key'] -> dict.get('key', '')""" if not line_number: return False key = error.get('details', {}).get('key') if not key: return False content = file_path.read_text() lines = content.splitlines() if li ...[truncated 3668 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
builder/correction/fixer.py:188
Finding

Automatic GLM Correction Transmits Complete Source Files Without Secret Redaction

Content
View full analysis
bool: """GLM API로 수정 (Simple 프로젝트용)""" if not self.glm_api_key: logger.warning("GLM API key not configured") return False try: import urllib.request import json # GLM API 호출 (ZhipuAI / ChatGLM format) # 에러 컨텍스트와 파일 내용 전송 file_content = file_path.read_text() prompt = f"""Fix the following error in this Python code: Error Type: {error.get('type')} Error Details: {error.get('raw_output', '')[:500]} File: {file_path} Line: {error.get('line_number', '?')} Code: ```python {file_content} ``` Return ONLY the fixed Python code, no explanations. """ data = { "model": "glm-4", "messages": [ {"role": "user", "content": prompt} ], "temperature": 0.1 } req = urllib.request.Request( "https://open.bigmodel.cn/api/paas/v4/chat/completions", data=json.dumps(data).encode('utf-8'), headers={ 'Authorization': f'Bearer {self.glm_api_key}', 'Content-Type': 'application/json' } ) with urllib.request.urlopen(req, timeout=30) as response: result = json.loads(response.read().decode()) content = result['choices'][0]['message']['content'] if '```' in content: code_lines = content.split('```')[1].split('\n') if code_lines[0].startswith('python'): code_lines = code_lines[1:] fixed_code = '\n'.join(code_lines).rstrip() else: fixed_code = content.strip() backup_path = file_p ...[truncated 2155 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
builder/integration/github_publisher.py:71
Finding

GitHub Publisher Stages All Files and Defaults to Public Repositories

Content
View full analysis
Dict: """프로젝트를 GitHub에 퍼블리싱 Steps: 1. git 초기화 2. GitHub repo 생성 3. commit & push 4. release 생성 """ title = project_info.get('title', 'Untitled Project') repo_name = self._sanitize_repo_name(title) description = project_info.get('description', '')[:200] try: self._init_git(project_path) repo_url = self._create_repo(repo_name, description) self._push_to_github(project_path, repo_url) self._create_release(project_path, title, description) logger.info("Published: https://github.com/%s", repo_url.replace('git@github.com:', '').replace('.git', '')) return { 'success': True, 'repo_name': repo_name, 'url': repo_url } except Exception as e: logger.warning("Publish failed: %s", e) return { 'success': False, 'error': str(e) } ``` ```python def _init_git(self, project_path: Path): """git 초기화""" subprocess.run(['git', 'init'], cwd=str(project_path), capture_output=True, check=True) subprocess.run(['git', 'add', '.'], cwd=str(project_path), capture_output=True, check=True) subprocess.run(['git', 'commit', '-m', 'Initial commit'], cw ...[truncated 2793 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
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (190)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The description advertises automated development and publishing but does not prominently warn that the skill can create repositories and push generated code to GitHub. That omission is dangerous because users may invoke the skill expecting local assistance, while the documented workflow includes external publication and release creation that could expose sensitive code or create unwanted public artifacts.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
91% confidence
Finding

The skill requires users to place multiple high-value secrets in a local .env file for autonomous use by the agent, including GitHub and Notion credentials plus a model API key. In the context of an agent that performs automated external actions and code generation, centralizing these credentials increases the blast radius if the environment, logs, generated code, or repository contents are mishandled.

Content

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

4. 환경 변수 설정

bash
cp .env.example .env

.env 파일 수정:

Credential Access

High
Category
Privilege Escalation
Confidence
86% confidence
Finding

Declaring a GitHub Personal Access Token as a dependency signals that the skill depends on a powerful credential to create repositories and publish code. In this skill's context, that is especially dangerous because the pipeline is autonomous and may create or push artifacts without sufficient review, making token misuse or over-privilege impactful.

Content

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

md
- Python 3.11+
- ChatDev 2.0
- GLM-5 API
- GitHub Personal Access Token
- Notion API

## 라이선스

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · acp_self_correction.py (reported line 165)May include surrounding context.

python
Return the fixed code or explain what needs to be changed.
"""
        return prompt
    
    def _apply_fix_locally(self, error: Dict) -> Dict:
        """로컬에서 직접 수정 적용"""

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · builder/orchestrator.py (reported line 244)May include surrounding context.

python
Return the fixed code or explain what needs to be changed.
"""
        return prompt
    
    def _apply_fix_locally(self, error: Dict) -> Dict:
        """로컬에서 직접 수정 적용"""

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
98% confidence
Finding

The subprocess environment is built by copying all of os.environ, which exposes host secrets to the test process. Because the executed test suite comes from the target project and may be untrusted, this is a direct secret-harvesting path and substantially more dangerous in a self-correcting agent that automatically runs code.

Content

Scanner excerpt · acp_self_correction.py (reported line 277)May include surrounding context.

python
capture_output=True,
                text=True,
                timeout=30,
                env={**os.environ, 'PYTHONPATH': 'src'}
            )
            
            return {

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
94% confidence
Finding

The subprocess environment inherits the full parent os.environ and only overrides PYTHONPATH, which can expose sensitive environment variables such as API keys, tokens, and credentials to untrusted test code. Since the invoked tests execute arbitrary project Python, they can read and exfiltrate inherited secrets, making this especially dangerous in an automated agent context.

Content

Scanner excerpt · builder/correction/base.py (reported line 45)May include surrounding context.

python
capture_output=True,
                text=True,
                timeout=timeout,
                env={**os.environ, 'PYTHONPATH': 'src'}
            )

            return {

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The auto-fixer transmits the full source code to an external API as part of normal operation without any visible justification, minimization, or consent flow. In a code-building agent, this is especially dangerous because repositories often contain proprietary logic, credentials, and internal infrastructure details.

Content

No source excerpt is available for this finding.

Tainted flow: 'req' from pathlib.Path.read_text (line 225, file read) → urllib.request.urlopen (network output)

High
Category
Data Flow
Confidence
99% confidence
Finding

The fixer sends full file contents and error context to a third-party API over the network. This can exfiltrate proprietary code, secrets embedded in source, or sensitive paths/log data, and the transmitted content is derived directly from local project files.

Content

Scanner excerpt · builder/correction/fixer.py (reported line 234)May include surrounding context.

python
}
            )

            with urllib.request.urlopen(req, timeout=30) as response:
                result = json.loads(response.read().decode())
                content = result['choices'][0]['message']['content']

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The fixer delegates remediation to an external CLI with Bash/Edit/Write permissions over the project. This materially exceeds a narrowly scoped 'code fixer' role and gives an LLM-backed tool direct capability to execute commands and alter repository contents.

Content

No source excerpt is available for this finding.

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
93% confidence
Finding

Passing the full parent process environment into an external CLI exposes all environment variables, which commonly include API keys, cloud credentials, tokens, and internal endpoints. In combination with a command-capable tool, this meaningfully increases the blast radius if the delegated agent is compromised or induced to disclose secrets.

Content

Scanner excerpt · builder/correction/fixer.py (reported line 283)May include surrounding context.

python
'claude', '-p', prompt,
                '--allowedTools', 'Edit,Write,Bash'
            ], cwd=str(project_path), capture_output=True, text=True,
               timeout=120, env={**os.environ,
                'CLAUDE_OUTPUT_DIR': str(project_path)})

            if result.returncode == 0:

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

md
}

    def _load_token(self) -> Optional[str]:
        """.env 파일에서 Notion API 토큰 로드"""
        env_file = Path.home() / '.openclaw' / 'workspace' / '.env'
        if env_file.exists():
            for line in env_file.read_text().splitlines():

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 28)May include surrounding context.

md
}

    def _load_token(self) -> Optional[str]:
        """.env 파일에서 Notion API 토큰 로드"""
        env_file = Path.home() / '.openclaw' / 'workspace' / '.env'
        if env_file.exists():
            for line in env_file.read_text().splitlines():

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 29)May include surrounding context.

md
}

    def _load_token(self) -> Optional[str]:
        """.env 파일에서 Notion API 토큰 로드"""
        env_file = Path.home() / '.openclaw' / 'workspace' / '.env'
        if env_file.exists():
            for line in env_file.read_text().splitlines():

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 · builder/integration/notion_sync.py (reported line 27)May include surrounding context.

python
}

    def _load_token(self) -> Optional[str]:
        """.env 파일에서 Notion API 토큰 로드"""
        env_file = Path.home() / '.openclaw' / 'workspace' / '.env'
        if env_file.exists():
            for line in env_file.read_text().splitlines():

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

python
}

    def _load_token(self) -> Optional[str]:
        """.env 파일에서 Notion API 토큰 로드"""
        env_file = Path.home() / '.openclaw' / 'workspace' / '.env'
        if env_file.exists():
            for line in env_file.read_text().splitlines():

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 · builder/integration/notion_sync.py (reported line 28)May include surrounding context.

python
def _load_token(self) -> Optional[str]:
        """.env 파일에서 Notion API 토큰 로드"""
        env_file = Path.home() / '.openclaw' / 'workspace' / '.env'
        if env_file.exists():
            for line in env_file.read_text().splitlines():
                if line.startswith('NOTION_API_KEY='):

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

python
def _load_token(self) -> Optional[str]:
        """.env 파일에서 Notion API 토큰 로드"""
        env_file = Path.home() / '.openclaw' / 'workspace' / '.env'
        if env_file.exists():
            for line in env_file.read_text().splitlines():
                if line.startswith('NOTION_API_KEY='):

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · builder/orchestrator.py (reported line 89)May include surrounding context.

python
'--output-format', 'json',
                '--allowedTools', 'Edit,Write,Bash'
            ], cwd=str(project_path), capture_output=True, text=True,
               timeout=self.claude_timeout, env={**os.environ,
                'CLAUDE_OUTPUT_DIR': str(project_path)})

            if result.returncode == 0:

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · builder/orchestrator.py (reported line 170)May include surrounding context.

python
'--output-format', 'json',
                '--allowedTools', 'Edit,Write,Bash'
            ], cwd=str(project_path), capture_output=True, text=True,
               timeout=self.claude_timeout, env={**os.environ,
                'CLAUDE_OUTPUT_DIR': str(project_path)})

            if result.returncode == 0:

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
90% confidence
Finding

Passing {**os.environ, 'PYTHONPATH': 'src'} forwards the full parent process environment into untrusted test execution. If the host environment contains API keys, tokens, cloud credentials, or internal endpoints, malicious test code can read and exfiltrate them, making this a meaningful secret-exposure issue in combination with arbitrary code execution.

Content

Scanner excerpt · builder/pipeline.py (reported line 182)May include surrounding context.

python
capture_output=True,
                text=True,
                timeout=30,
                env={**os.environ, 'PYTHONPATH': 'src'}
            )

            return {

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
95% confidence
Finding

The subprocess inherits the full host environment via os.environ, which can expose secrets such as API keys, tokens, proxy credentials, and CI metadata to untrusted test code. In this skill's context, tests are executed from the target project, so any malicious test can read and exfiltrate those variables.

Content

Scanner excerpt · builder/testing/runner.py (reported line 40)May include surrounding context.

python
capture_output=True,
                text=True,
                timeout=self.timeout,
                env={**os.environ, 'PYTHONPATH': 'src'}
            )

            output = result.stdout + result.stderr

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
97% confidence
Finding

This specific-test execution path also forwards the entire parent environment to code chosen by the repository or caller. That enables malicious tests to harvest credentials and other sensitive runtime context directly from environment variables.

Content

Scanner excerpt · builder/testing/runner.py (reported line 81)May include surrounding context.

python
capture_output=True,
                text=True,
                timeout=self.timeout,
                env={**os.environ, 'PYTHONPATH': 'src'}
            )

            output = result.stdout + result.stderr

Credential Access

High
Category
Privilege Escalation
Confidence
98% confidence
Finding

The function explicitly targets a local .env file in the user's workspace to extract a Notion API key. Directly searching for and reading credentials from local storage is sensitive behavior and, in a skill that can also call external APIs, materially increases the risk of unauthorized credential use and secret exfiltration.

Content

Scanner excerpt · discovery_layer.py (reported line 389)May include surrounding context.

python
def _get_notion_token(self) -> Optional[str]:
        """Notion API 토큰 가져오기"""
        
        # .env 파일에서 읽기
        env_file = Path.home() / '.openclaw' / 'workspace' / '.env'
        
        if env_file.exists():

Credential Access

High
Category
Privilege Escalation
Confidence
98% confidence
Finding

Opening and parsing the identified .env file to locate NOTION_API_KEY constitutes active credential access. In the surrounding skill context, this is more dangerous because the token is then used for network writes, creating an end-to-end path from local secret collection to external service use without clear disclosure.

Content

Scanner excerpt · discovery_layer.py (reported line 390)May include surrounding context.

python
"""Notion API 토큰 가져오기"""
        
        # .env 파일에서 읽기
        env_file = Path.home() / '.openclaw' / 'workspace' / '.env'
        
        if env_file.exists():
            with open(env_file, 'r') as f:

Static analysis

No suspicious patterns detected.