# SkillSpector Dangerous Function Calls: AST Analyzer Detection Patterns

> SkillSpector's AST analyzer detects dangerous function calls in Python code, including execution APIs, subprocess, OS spawners, and dynamic access. Secure your code now.

- Repository: [NVIDIA Corporation/SkillSpector](https://github.com/NVIDIA/SkillSpector)
- Tags: internals
- Published: 2026-06-21

---

**SkillSpector’s behavioral AST analyzer identifies dangerous function calls by scanning Python source files for built-in execution APIs, subprocess and OS process spawners, dynamic attribute access, and dangerous execution chains that wrap high-risk operations.**

NVIDIA’s SkillSpector employs a static analysis engine to detect unsafe code execution patterns in AI-generated skills. The analyzer evaluates Python source files against a curated list of dangerous function signatures defined in [`src/skillspector/nodes/analyzers/behavioral_ast.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/analyzers/behavioral_ast.py), generating SARIF findings with rule IDs AST1 through AST8.

## Built-in Execution APIs (AST1, AST2, AST6)

The analyzer flags calls to Python’s built-in functions that can execute arbitrary code. According to lines 32-33 of [`behavioral_ast.py`](https://github.com/NVIDIA/SkillSpector/blob/main/behavioral_ast.py), this category includes `exec()`, `eval()`, `compile()`, and `__import__()`.

These functions allow dynamic code execution or module loading, making them primary targets for injection attacks. When the analyzer encounters these calls via the `_analyze_python` function, it emits findings with high severity and confidence scores.

```python

# AST1 - exec()

exec("print('dangerous')")

# AST2 - eval()

result = eval("2 + 2")

# AST6 - compile()

code_obj = compile("x = 1", "<string>", "exec")

```

## Subprocess Module Calls (AST4)

Any function from the `subprocess` module that spawns external processes triggers rule AST4. Lines 34-44 of [`behavioral_ast.py`](https://github.com/NVIDIA/SkillSpector/blob/main/behavioral_ast.py) define this set as `subprocess.call`, `subprocess.run`, `subprocess.Popen`, `subprocess.check_output`, `subprocess.check_call`, `subprocess.getoutput`, and `subprocess.getstatusoutput`.

These calls create command injection risks when user input reaches the shell. The analyzer uses `resolve_call_name` from [`src/skillspector/nodes/analyzers/common.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/analyzers/common.py) to resolve imported names and match them against this dangerous set.

```python
import subprocess

subprocess.run(["rm", "-rf", "/"])          # AST4

subprocess.Popen("ls -la", shell=True)     # AST4

subprocess.check_output("whoami", shell=True)  # AST4

```

## OS Exec-Family Calls (AST5)

The analyzer detects 21 distinct functions from the `os` module that execute or spawn system processes. Lines 46-68 of [`behavioral_ast.py`](https://github.com/NVIDIA/SkillSpector/blob/main/behavioral_ast.py) enumerate the complete list including `os.system`, `os.popen`, all `os.exec*` variants (`execl`, `execle`, `execlp`, `execlpe`, `execv`, `execve`, `execvp`, `execvpe`), and all `os.spawn*` variants (`spawnl`, `spawnle`, `spawnlp`, `spawnlpe`, `spawnv`, `spawnve`, `spawnvp`, `spawnvpe`), plus `os.posix_spawn` and `os.posix_spawnp`.

These low-level system calls bypass Python’s safety mechanisms, warranting immediate flagging with critical severity.

```python
import os

os.system("ls /tmp")                        # AST5

os.execv("/bin/ls", ["ls", "/tmp"])        # AST5

```

## Dynamic Attribute Access (AST7)

SkillSpector flags `getattr()` calls where the attribute name is not a constant literal. Lines 78-84 of [`behavioral_ast.py`](https://github.com/NVIDIA/SkillSpector/blob/main/behavioral_ast.py) implement this check to detect reflection-based attacks where user-controlled input determines which method or attribute to access.

Dynamic attribute retrieval enables attackers to invoke private methods or bypass access controls when the second argument derives from external input.

```python
obj = SomeClass()
attr_name = input("attribute?")   # user-controlled

value = getattr(obj, attr_name)    # AST7 - flagged because attr_name is not constant

```

## Dangerous Execution Chains (AST8)

The most severe pattern occurs when `exec()`, `eval()`, or `compile()` wraps any dangerous source including subprocess calls, OS exec functions, `__import__()`, or network-related helpers. Lines 71-80 of [`behavioral_ast.py`](https://github.com/NVIDIA/SkillSpector/blob/main/behavioral_ast.py) implement this chain detection, reporting it as rule AST8 with a 0.95 confidence score.

This pattern indicates an attempt to obfuscate malicious code execution by nesting dangerous calls within evaluation contexts.

```python
import subprocess

exec("subprocess.run(['rm', '-rf', '/'])")   # AST8 - dangerous chain detected

```

## How the Detection Engine Works

The core detection logic resides in the `_analyze_python` function within [`src/skillspector/nodes/analyzers/behavioral_ast.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/analyzers/behavioral_ast.py). The analyzer walks the AST and uses `resolve_call_name` from [`src/skillspector/nodes/analyzers/common.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/analyzers/common.py) to fully qualify function references, handling imports and aliases.

When a match occurs against the dangerous call sets defined in lines 32-68, the analyzer constructs an `AnalyzerFinding` object (defined in [`src/skillspector/models.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/models.py)) containing the rule ID, file location, code snippet, severity level, and remediation guidance. The [`meta_analyzer.py`](https://github.com/NVIDIA/SkillSpector/blob/main/meta_analyzer.py) orchestrator aggregates these findings into the final SARIF report.

## Summary

- **SkillSpector detects five categories of dangerous function calls** through its behavioral AST analyzer: built-in execution APIs, subprocess spawners, OS exec-family functions, dynamic attribute access, and dangerous execution chains.
- **Rule IDs AST1 through AST8** map to specific dangerous patterns with severity ratings ranging from high to critical and confidence scores up to 0.95.
- **The detection logic** is implemented in [`src/skillspector/nodes/analyzers/behavioral_ast.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/analyzers/behavioral_ast.py) with helper functions in [`common.py`](https://github.com/NVIDIA/SkillSpector/blob/main/common.py) and data models in [`models.py`](https://github.com/NVIDIA/SkillSpector/blob/main/models.py).
- **Code examples** demonstrate how `exec()`, `subprocess.run`, `os.system`, `getattr()` with variables, and nested execution chains trigger analyzer findings.

## Frequently Asked Questions

### What confidence score does SkillSpector assign to dangerous execution chains?

SkillSpector assigns AST8 findings a confidence score of 0.95, indicating high certainty that the pattern represents a dangerous execution chain where `exec()`, `eval()`, or `compile()` wraps other high-risk operations.

### How does SkillSpector distinguish safe from dangerous getattr calls?

The analyzer inspects the AST node for the second argument to `getattr()` as implemented in lines 78-84 of [`behavioral_ast.py`](https://github.com/NVIDIA/SkillSpector/blob/main/behavioral_ast.py). If the attribute name is not a constant literal (e.g., a string variable or concatenated value), it triggers rule AST7; constant literals like `getattr(obj, "method")` are not flagged.

### Which file contains the core detection logic for dangerous function calls?

The core detection logic resides in [`src/skillspector/nodes/analyzers/behavioral_ast.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/analyzers/behavioral_ast.py), specifically within the `_analyze_python` function and the dangerous call sets defined at lines 32-68. Helper functions for name resolution are located in [`src/skillspector/nodes/analyzers/common.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/analyzers/common.py).

### What severity levels does SkillSpector use for dangerous function calls?

SkillSpector assigns severity levels ranging from **high** to **critical** depending on the specific dangerous pattern. Built-in execution APIs and subprocess calls typically receive high severity, while OS exec-family calls and dangerous execution chains (AST8) receive critical severity ratings.