Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: Docs

on:
push:
branches: [main]
paths:
- "docs/**"
- "mkdocs.yml"
- ".github/workflows/docs.yml"
- "CHANGELOG.md"
- "skills/**"
- "examples/**"
- "README.md"
workflow_dispatch:

permissions:
contents: read
pages: write
id-token: write

concurrency:
group: pages
cancel-in-progress: false

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Cache pip
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: docs-pip
- name: Install dependencies
run: |
pip install \
mkdocs-material \
mkdocs-mermaid2-plugin \
mkdocs-git-revision-date-localized-plugin \
pymdown-extensions
- name: Build site
run: mkdocs build --strict
- uses: actions/upload-pages-artifact@v3
with:
path: site/

deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- id: deployment
uses: actions/deploy-pages@v4
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.DS_Store
*.log
node_modules/
site/
1 change: 1 addition & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--8<-- "CHANGELOG.md"
66 changes: 66 additions & 0 deletions docs/comparison.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Comparativo

ShieldCode vs outras formas de hardening de código.

## Snyk Code, GitHub Advanced Security, Sonar

| Aspecto | ShieldCode | SAST tools |
|---------|-----------|------------|
| Quando age | Durante geração | Após código escrito |
| Granularidade | Padrão por padrão | Vulnerabilidade por vulnerabilidade |
| Custo | $0 | Pago (SaaS) |
| Cobertura | Padrões comuns (4 hoje, mais vindo) | Bibliotecas grandes de CVEs |
| Falsos positivos | Zero (não detecta, previne) | Médio-alto |
| Educação | Alta (explica cada padrão) | Baixa (só aponta) |

**Combine ambos**: ShieldCode previne os 80% mais comuns durante a geração, SAST cobre os 20% restantes e CVEs específicos de libs.

## Bandit / Semgrep

Linters de segurança open source. ShieldCode complementa:

- **Bandit/Semgrep**: detectam após escrita
- **ShieldCode**: previne durante geração

Bandit pode rodar em CI verificando que ShieldCode foi aplicado. Defense-in-depth.

## OWASP Cheat Sheets

OWASP mantém cheat sheets pra cada vulnerabilidade. ShieldCode é a **versão acionável** dessas cheat sheets pra agentes de IA:

- OWASP cheat sheet diz "use parametrização em SQL"
- ShieldCode FAZ o Claude usar parametrização toda vez

## Por que skill é melhor que prompt engineering manual

Sem ShieldCode, você teria que lembrar de pedir:

> "Faz endpoint Y mas usa parametrização SQL pra prevenir injection, escape HTML do input do usuário, valida URL antes de fazer request, canonicaliza path antes de salvar..."

Com ShieldCode, você só pede:

> "Faz endpoint Y"

E a skill garante todos os padrões. Você não precisa lembrar — o sistema lembra por você.

## Por que skill em vez de fine-tuning

Fine-tuning seria a melhor solução em teoria. Mas:

- Caro (precisa de dataset grande, GPU, tempo)
- Específico de modelo (não funciona em todos os Claude / GPT / Gemini)
- Não é atualizável rápido (padrões de segurança evoluem)

Skill em markdown é hackável, gratuita, atualizável em segundos.

## Limitações

ShieldCode reduz risco de classes comuns de vulnerabilidade. NÃO substitui:

- **Pentesting** (encontra problemas que escapam de SAST e generators)
- **Code review** humano (julgamento contextual)
- **Threat modeling** (decisões arquiteturais)
- **Dependency scanning** (CVEs em libs)
- **Runtime protection** (WAF, RASP)

É uma layer adicional, não a única.
47 changes: 47 additions & 0 deletions docs/contributing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Contribuir

## Como ajudar

- **Novos cenários OWASP**: adicionar exemplos em `examples/`
- **Mais frameworks**: criar páginas em `docs/frameworks/`
- **Issues**: reportar bugs ou pedir features em [github.com/nikolasdehor/shieldcode/issues](https://github.com/nikolasdehor/shieldcode/issues)
- **Casos reais**: compartilhar como você usa

## Adicionar novo cenário OWASP

1. Crie `examples/<vulnerabilidade>/` com:
- `vulnerable.py` — código exemplo VULNERÁVEL com comentários explicando o ataque
- `hardened.py` — versão SEGURA com comentários explicando a mitigação
- `README.md` — explicação curta + referências OWASP / CWE
2. Atualize `skills/shieldcode/SKILL.md` adicionando a regra
3. Crie página em `docs/vulns/<vulnerabilidade>.md`
4. Adicione à navegação em `mkdocs.yml`

## Setup dev

```bash
git clone https://github.com/nikolasdehor/shieldcode
cd shieldcode
./install.sh --scope=project
```

## Testar a skill localmente

No Claude Code:

```
"Use a skill shieldcode. Faz endpoint Flask que recebe filename do usuário e serve o arquivo."
```

Você deve receber:

- Código `hardened` (com canonicalização de path)
- Explicação clara sobre path traversal
- Sugestão de defenses adicionais

## Padrões

- Português pt-BR com acentos corretos em docs e comentários
- Inglês em código (identifiers, variable names)
- Mensagens de commit em imperativo, sem AI footers
- Markdown limpo, code blocks com linguagem especificada
73 changes: 73 additions & 0 deletions docs/frameworks/django.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Django

ShieldCode aplica padrões idiomáticos do Django para cada cenário.

## SQL Injection

O Django ORM é **safe by default**. ShieldCode reforça:

- ✅ Use querysets: `User.objects.filter(name=name)`
- ❌ Evite `.raw()` ou `.extra()` com input do usuário
- Se precisar de SQL puro, use parâmetros:
```python
User.objects.raw("SELECT * FROM users WHERE name = %s", [name])
```

## XSS

Django templates **auto-escape** por default:

```html
{# SEGURO automaticamente #}
<h1>Olá {{ nome }}</h1>
```

ShieldCode alerta quando vir `|safe`, `mark_safe()` ou `{% autoescape off %}`.

## CSRF

Django tem CSRF protection embutido. ShieldCode garante:

- `{% csrf_token %}` em todo formulário
- `@csrf_exempt` só quando absolutamente necessário (e justificado em comentário)

## SSRF

Django não tem proteção embutida. ShieldCode aplica os padrões genéricos de [SSRF](../vulns/ssrf.md).

## Settings de segurança

ShieldCode sugere garantir no `settings.py`:

```python
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
SECURE_CONTENT_TYPE_NOSNIFF = True
SECURE_BROWSER_XSS_FILTER = True
X_FRAME_OPTIONS = "DENY"
```

## Dependências auxiliares

ShieldCode sugere:

- `django-axes` (rate limit de login)
- `django-csp` (Content-Security-Policy)
- `django-security` (vários middlewares de segurança)
- `bandit` em CI

## Exemplo prático

> "Faz um endpoint Django REST que cadastra usuário com email e senha"

ShieldCode entrega:

- Serializer com validação (`EmailField`, `min_length=8` na senha)
- View com `permission_classes = [AllowAny]` explícito (para cadastro)
- Senha hasheada via `set_password()` (não em plaintext)
- Rate limit via `django-axes` ou DRF throttling
- Resposta sem expor IDs internos
133 changes: 133 additions & 0 deletions docs/frameworks/express.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# Express / Node.js

ShieldCode aplica padrões idiomáticos do Express e ecossistema Node.

## SQL Injection

Use ORM ou drivers com parametrização:

```javascript
// Prisma (recomendado)
const user = await prisma.user.findUnique({ where: { email } });

// pg (driver Postgres) parametrizado
await db.query("SELECT * FROM users WHERE name = $1", [name]);

// mysql2 prepared statements
await db.execute("SELECT * FROM users WHERE name = ?", [name]);
```

## Input validation

Use Zod:

```typescript
import { z } from "zod";

const UserSchema = z.object({
email: z.string().email(),
password: z.string().min(8).max(128),
});

app.post("/users", (req, res) => {
const parsed = UserSchema.safeParse(req.body);
if (!parsed.success) {
return res.status(400).json({ errors: parsed.error.errors });
}
// parsed.data tem tipos corretos
});
```

## XSS prevention

Use template engines com auto-escape (Pug, EJS com `<%- %>` cuidadoso, Handlebars):

```javascript
// Sem escape: VULNERÁVEL em EJS
<%- userInput %>

// Com escape: SEGURO em EJS
<%= userInput %>
```

Em SPAs (React, Vue, Svelte), frameworks escapam por padrão.

## Helmet (security headers)

```javascript
import helmet from "helmet";

app.use(helmet()); // CSP, HSTS, X-Frame-Options, etc

app.use(helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'nonce-RANDOM'"],
},
}));
```

## Auth (passport / jose)

Para JWT, prefira `jose` (moderno) ou `jsonwebtoken`:

```javascript
import { SignJWT, jwtVerify } from "jose";

const secret = new TextEncoder().encode(process.env.JWT_SECRET);

const token = await new SignJWT({ sub: userId })
.setProtectedHeader({ alg: "HS256" })
.setExpirationTime("15m")
.sign(secret);
```

Senha: use `bcrypt` ou `argon2`:

```javascript
import bcrypt from "bcrypt";

const hash = await bcrypt.hash(password, 12);
const valid = await bcrypt.compare(password, hash);
```

## Rate limit

```javascript
import rateLimit from "express-rate-limit";

const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 min
max: 5,
});

app.post("/login", loginLimiter, loginHandler);
```

## CORS

```javascript
import cors from "cors";

app.use(cors({
origin: ["https://meu-frontend.com"],
credentials: true,
}));
```

NUNCA `origin: "*"` com `credentials: true`.

## Exemplo prático

> "Faz API Express com login JWT e CRUD de posts"

ShieldCode entrega:

- Helmet ON
- Zod validando body em todo POST/PUT
- Senha hasheada com bcrypt cost 12
- JWT com expiração 15min + refresh tokens
- Rate limit no login (5/15min)
- Posts: SQL via Prisma (zero injection)
- Auth middleware (`Bearer token` obrigatório)
- CORS restrito ao frontend conhecido
Loading
Loading