Mixed-Language Monorepo Security Analysis
Purpose
Provide comprehensive guidance for security analysis of polyglot codebases where multiple services are written in different programming languages. These are increasingly common in modern architectures (Go APIs + Python ML + TypeScript frontends).
When to Use
Activate this skill when:
- Monorepo contains services in 2+ different languages
- Microservices architecture with polyglot stack
- User mentions "Go + Python", "TypeScript + Java", etc.
- Cross-service API security analysis needed
- gRPC/protobuf, OpenAPI, or GraphQL schemas present
Core Challenges
Why Mixed-Language is Different
| Single-Language | Mixed-Language |
|---|---|
| One compression strategy | Per-service strategy needed |
| Unified sink database | Multiple sink databases |
| Same vulnerability patterns | Language-specific + cross-service patterns |
| Simple trust boundaries | Complex inter-service boundaries |
| One toolchain | Multiple toolchains (Semgrep rules vary) |
Common Polyglot Patterns
| Pattern | Example | Security Concern |
|---|---|---|
| API Gateway + Services | Go gateway → Python/Java services | Gateway bypass, auth propagation |
| BFF + Backend | TS frontend → Go API → Python ML | Input validation gaps |
| Event-Driven | Services communicate via Kafka/RabbitMQ | Message injection, schema drift |
| Sidecar/Service Mesh | Envoy/Istio + any language | mTLS config, RBAC policies |
Detection
Step 1: Identify All Languages
# Count files by language
echo "=== Language Distribution ==="
echo "Go: $(find . -name '*.go' ! -path '*/vendor/*' ! -name '*_test.go' 2>/dev/null | wc -l)"
echo "Python: $(find . -name '*.py' ! -path '*/.venv/*' ! -path '*/venv/*' ! -name 'test_*.py' 2>/dev/null | wc -l)"
echo "TypeScript: $(find . \( -name '*.ts' -o -name '*.tsx' \) ! -path '*/node_modules/*' ! -name '*.test.*' ! -name '*.spec.*' 2>/dev/null | wc -l)"
echo "JavaScript: $(find . \( -name '*.js' -o -name '*.jsx' \) ! -path '*/node_modules/*' ! -name '*.test.*' ! -name '*.spec.*' 2>/dev/null | wc -l)"
echo "Java: $(find . -name '*.java' ! -path '*/test/*' ! -name '*Test.java' 2>/dev/null | wc -l)"
echo "Rust: $(find . -name '*.rs' ! -path '*/target/*' ! -name '*_test.rs' 2>/dev/null | wc -l)"
echo "PHP: $(find . -name '*.php' ! -path '*/vendor/*' ! -name '*Test.php' 2>/dev/null | wc -l)"
echo "C#: $(find . -name '*.cs' ! -path '*/bin/*' ! -path '*/obj/*' ! -name '*Test*.cs' 2>/dev/null | wc -l)"
echo "Ruby: $(find . -name '*.rb' ! -path '*/vendor/*' ! -name '*_spec.rb' ! -name '*_test.rb' 2>/dev/null | wc -l)"
echo "Solidity: $(find . -name '*.sol' ! -path '*/node_modules/*' ! -name '*Test.sol' 2>/dev/null | wc -l)"
Step 2: Map Services to Languages
# Find service boundaries (look for entrypoints)
echo "=== Service Discovery ==="
# Go services (main.go or cmd/)
find . -name 'main.go' -o -type d -name 'cmd' 2>/dev/null | head -20
# Python services (main.py, app.py, manage.py, __main__.py)
find . \( -name 'main.py' -o -name 'app.py' -o -name 'manage.py' -o -name '__main__.py' \) 2>/dev/null | head -20
# TypeScript/JS services (package.json with "start" script)
find . -name 'package.json' ! -path '*/node_modules/*' -exec grep -l '"start"' {} \; 2>/dev/null | head -20
# Java services (Application.java, pom.xml, build.gradle)
find . \( -name '*Application.java' -o -name 'pom.xml' -o -name 'build.gradle' \) ! -path '*/test/*' 2>/dev/null | head -20
# Rust services (Cargo.toml with [[bin]])
find . -name 'Cargo.toml' -exec grep -l '\[\[bin\]\]' {} \; 2>/dev/null | head -20
# Docker/container indicators
find . -name 'Dockerfile*' -o -name 'docker-compose*.yml' -o -name 'docker-compose*.yaml' 2>/dev/null | head -20
Step 3: Detect Inter-Service Communication
# Protocol definitions
echo "=== Communication Protocols ==="
# gRPC/Protobuf
find . -name '*.proto' 2>/dev/null | head -10
echo "Proto files: $(find . -name '*.proto' 2>/dev/null | wc -l)"
# OpenAPI/Swagger
find . \( -name 'openapi*.yaml' -o -name 'openapi*.yml' -o -name 'openapi*.json' -o -name 'swagger*.yaml' -o -name 'swagger*.yml' -o -name 'swagger*.json' \) 2>/dev/null | head -10
# GraphQL
find . \( -name '*.graphql' -o -name '*.gql' -o -name 'schema.graphql' \) 2>/dev/null | head -10
# Thrift
find . -name '*.thrift' 2>/dev/null | head -5
# Message queues (Kafka, RabbitMQ, etc.)
grep -rniE "(kafka|rabbitmq|amqp|pulsar|nats)" --include="*.yaml" --include="*.yml" --include="*.json" --include="*.toml" . 2>/dev/null | head -10
Service Mapping Output
After detection, produce a service map:
## Service Architecture Map
| Service | Path | Language | Entry Point | Communication |
|---------|------|----------|-------------|---------------|
| api-gateway | services/gateway/ | Go | cmd/gateway/main.go | gRPC (internal), REST (external) |
| auth-service | services/auth/ | Go | cmd/auth/main.go | gRPC |
| ml-pipeline | services/ml/ | Python | src/main.py | REST, Kafka consumer |
| web-frontend | apps/web/ | TypeScript | src/index.tsx | REST client |
| data-processor | services/processor/ | Java | src/.../Application.java | Kafka producer/consumer |
### Inter-Service Flows
```mermaid
graph LR
A[web-frontend<br/>TypeScript] -->|REST| B[api-gateway<br/>Go]
B -->|gRPC| C[auth-service<br/>Go]
B -->|gRPC| D[ml-pipeline<br/>Python]
D -->|Kafka| E[data-processor<br/>Java]
E -->|Kafka| D
## Per-Service Scoping Strategy
### Multi-Service Scope Command
For polyglot monorepos, scope each service with its language-appropriate strategy:
```bash
# Step 1: Scope each service with language-appropriate compression
# Go service (97% compression)
npx repomix services/gateway --compress --style markdown \
--include "**/interfaces/**/*.go,**/handler/**/*.go,**/svc/**/*.go,**/api/**/*.go" \
--ignore "*_test.go,**/testing/**,**/*.pb.go" \
--output .claude/scope-gateway.md
# Python service (85-90% compression)
npx repomix services/ml --compress --style markdown \
--include "**/api/**/*.py,**/routes/**/*.py,**/models/**/*.py,**/schemas/**/*.py,**/services/**/*.py" \
--ignore "**/*_test.py,**/tests/**,**/__pycache__/**" \
--output .claude/scope-ml.md
# TypeScript frontend (80% compression)
npx repomix apps/web --compress --style markdown \
--ignore "**/node_modules/**,**/*.test.*,**/*.spec.*,**/dist/**" \
--output .claude/scope-web.md
# Java service (80-85% compression)
npx repomix services/processor --compress --style markdown \
--include "**/*Controller*.java,**/*Service*.java,**/*Repository*.java,**/model/**/*.java" \
--ignore "**/test/**,**/*Test.java,**/target/**" \
--output .claude/scope-processor.md
# Step 2: Scope shared protocol definitions (always include)
npx repomix proto/ --style markdown --output .claude/scope-proto.md
Unified Architecture Scope
Create a lightweight cross-service architecture view:
# Architecture-only scope (all languages, minimal detail)
npx repomix . --compress --style markdown \
--include "**/proto/**/*.proto,**/openapi*.yaml,**/swagger*.yaml,**/*.graphql,**/docker-compose*.yml,**/Dockerfile*,**/**/main.go,**/**/main.py,**/index.ts,**/*Application.java" \
--ignore "**/node_modules/**,**/vendor/**,**/target/**,**/.venv/**,**/dist/**,**/build/**" \
--output .claude/scope-architecture-overview.md
Cross-Service Security Analysis
Trust Boundaries
In polyglot monorepos, trust boundaries exist at:
| Boundary | Location | Security Concern |
|---|---|---|
| External → Gateway | API Gateway ingress | Input validation, rate limiting, auth |
| Gateway → Services | gRPC/REST internal calls | Auth token propagation, authz checks |
| Service → Service | Inter-service communication | Mutual TLS, service identity |
| Service → Data Store | D |