Skip to main content

What is Static Analysis?

Static analysis examines your source code without executing it. Unlike tests that run your code to check behavior, static analysis reads the code itself to find bugs, vulnerabilities, and quality issues.

Static vs Dynamic Analysis

AspectStatic AnalysisDynamic Analysis (Tests)
When it runsBefore/without executionDuring execution
What it seesAll code pathsOnly executed paths
SpeedFast (no runtime)Slower (needs execution)
CoverageComplete sourceDepends on test coverage
False positivesPossibleRare
False negativesPossibleDepends on tests

Why Static Analysis Matters

1. Finds Bugs Tests Miss

Tests only cover the paths you think to test. Static analysis examines every path:

def:

# process(data):
if data.type == "A":
return handle_a(data)
elif data.type == "B":
return handle_b(data)
# What if data.type == "C"? Tests might not cover this.
# Static analysis sees the uncovered branch.

2. Catches Issues Earlier

The earlier you find a bug, the cheaper it is to fix:

Static analysis catches issues at the code stage—before review, testing, or deployment.

3. Scales to Large Codebases

Manual code review doesn't scale:

Codebase SizeManual ReviewStatic Analysis
1K lines1 hour1 second
100K lines100 hours10 seconds
1M linesImpossible1 minute

4. Enforces Consistency

Static analysis applies rules uniformly. It doesn't:

  • Get tired on Friday afternoon
  • Forget to check that one file
  • Apply standards inconsistently

Types of Static Analysis

Syntactic Analysis (Linting)

Checks code style and structure without understanding meaning:

# Syntactic issues
import os # unused import - linter catches this
x=1+2 # spacing violation - linter catches this

Tools: Pylint, Flake8, ESLint, Ruff

Semantic Analysis

Understands meaning and relationships:

# Semantic issue: calling undefined function
def main():
result = proccess_data(x) # Typo: 'proccess' not defined

Tools: Pyright, mypy, TypeScript

Data Flow Analysis

Tracks how values move through code:

# Data flow issue: variable might be None
def get_user(id):
user = db.find(id) # Returns User or None
return user.name # user might be None!

Tools: Pyright (partial), Infer, Skylos

Taint Analysis

Traces untrusted data to dangerous operations:

# Taint issue: user input reaches SQL
user_input = request.args.get("q") # Source: tainted
query = f"SELECT * FROM t WHERE x = {user_input}" # Propagation
cursor.execute(query) # Sink: SQL execution

Tools: Semgrep, Snyk Code, Skylos


How Skylos Fits In

Skylos combines multiple analysis types:

Analysis TypeWhat Skylos Finds
SyntacticUnused imports
SemanticDead functions, classes, variables
Data FlowComplexity, nesting depth
TaintSQL injection, command injection, SSRF, XSS

Limitations of Static Analysis

Static analysis is powerful but not perfect:

Can't Understand Runtime Values

def:

# dynamic_call(func_name):
func = getattr(module, func_name) # Which function? Unknown at static time.
func()

Skylos uses confidence scoring to handle uncertainty.

Can't Prove Correctness

Static analysis finds potential issues. It can't prove your code is correct—only that it doesn't have known problems.

May Have False Positives

# Looks unused, but called via framework
@app.route("/users")
def get_users(): # Static analysis might miss the decorator
return users

Skylos uses framework awareness to reduce false positives.


Static Analysis in Your Workflow

The best time to run static analysis:

Pre-commit: Fast feedback, catch issues immediately CI Pipeline: Enforce standards, block bad PRs


Key Concepts Glossary

TermDefinition
ASTAbstract Syntax Tree—structured representation of code
TaintUntrusted data that could be dangerous
SourceWhere tainted data enters (user input, files)
SinkDangerous operation (SQL, shell, eval)
False positiveReported issue that isn't actually a problem
False negativeReal issue that wasn't detected
Cyclomatic complexityCount of independent paths through code

Next Steps

What is Dead Code?

Learn why unused code is dangerous

What is Taint Analysis?

Deep dive into security analysis