Skip to content
Development
Skill

/security

Build and harden Phoenix auth and security — OAuth login, password hashing, sessions, RBAC, rate limiting, CSRF, XSS, SQL injection, secrets. Use when adding login flows or permissions, or handling user input.

From plugin
claude-elixir-phoenix
574106 skills37 agents2 commands

Claude Code

$ npx -y skills add oliver-kriska/claude-elixir-phoenix --skill security --agent claude-code

SKILL.md

security.SKILL.md
name: security
description: "Build and harden Phoenix auth and security — OAuth login, password hashing, sessions, RBAC, rate limiting, CSRF, XSS, SQL injection, secrets. Use when adding login flows or permissions, or handling user input."
effort: medium
user-invocable: false
paths:
  - "**/*auth*.ex"
  - "**/*session*.ex"
  - "**/*password*.ex"

Elixir/Phoenix Security Reference

> **Ash projects**: `AshAuthentication` has its own strategy/token patterns — use the `ash-framework` skill. CSRF, XSS, and secret management patterns below still apply.

Quick reference for security patterns in Elixir/Phoenix.

Iron Laws — Never Violate These

1. **VALIDATE AT BOUNDARIES** — Never trust client input. All data through changesets 2. **NEVER INTERPOLATE USER INPUT** — Use Ecto's `^` operator, never string interpolation 3. **NO String.to_atom WITH USER INPUT** — Atom exhaustion DoS. Use `to_existing_atom/1` 4. **AUTHORIZE EVERYWHERE** — Check in contexts AND re-validate in LiveView events 5. **ESCAPE BY DEFAULT** — Never use `raw/1` with untrusted content 6. **SECRETS NEVER IN CODE** — All secrets in `runtime.exs` from env vars 7. **LIVEVIEW EVENT PARAMS ARE UNTRUSTED** — Users can alter forms, hooks, and every `phx-value-*` in DevTools. Validate and authorize against server-side state before acting

Quick Patterns

Timing-Safe Authentication

def authenticate(email, password) do
  user = Repo.get_by(User, email: email)

  cond do
    user && Argon2.verify_pass(password, user.hashed_password) ->
      {:ok, user}
    user ->
      {:error, :invalid_credentials}
    true ->
      Argon2.no_user_verify()  # Timing attack prevention
      {:error, :invalid_credentials}
  end
end

LiveView Authorization (CRITICAL)

# `id` is client input even when it came from phx-value-id.
# RE-AUTHORIZE IN EVERY EVENT HANDLER
def handle_event("delete", %{"id" => id}, socket) do
  post = Blog.get_post!(id)

  # Don't trust that mount authorized this action!
  with :ok <- Bodyguard.permit(Blog, :delete_post, socket.assigns.current_user, post) do
    Blog.delete_post(post)
    {:noreply, stream_delete(socket, :posts, post)}
  else
    _ -> {:noreply, put_flash(socket, :error, "Unauthorized")}
  end
end

Rendered LiveView events can expose IDs in HTML and websocket payloads. That is not automatically a vulnerability: treat IDs as public identifiers, never as proof of access. Use opaque references only when the identifier itself must not be disclosed, and still perform server-side authorization.

SQL Injection Prevention

# ✅ SAFE: Parameterized queries
from(u in User, where: u.name == ^user_input)

# ❌ VULNERABLE: String interpolation
from(u in User, where: fragment("name = '#{user_input}'"))

Quick Decisions

What to validate?

  • **All user input** → Ecto changesets
  • **File uploads** → Extension + magic bytes + size
  • **Paths** → `Path.safe_relative/2` for traversal
  • **Atoms** → `String.to_existing_atom/1` only

What to escape?

  • **HTML output** → Auto-escaped by default (`<%= %>`)
  • **User HTML** → HtmlSanitizeEx with scrubber
  • **Never** → `raw/1` with untrusted content

Anti-patterns

| Wrong | Right | |-------|-------| | `"SELECT * FROM users WHERE name = '#{name}'"` | `from(u in User, where: u.name == ^name)` | | `String.to_atom(user_input)` | `String.to_existing_atom(user_input)` | | `<%= raw @user_comment %>` | `<%= @user_comment %>` | | Hardcoded secrets in config | `runtime.exs` from env vars | | Auth only in mount | Re-auth in every `handle_event` | | Trusting `phx-value-*` or hidden IDs | Load server-side state and authorize it |

References

For detailed patterns, see:

  • `${CLAUDE_SKILL_DIR}/references/authentication.md` - phx.gen.auth, MFA, sessions
  • `${CLAUDE_SKILL_DIR}/references/authorization.md` - Bodyguard, scopes, LiveView auth
  • `${CLAUDE_SKILL_DIR}/references/input-validation.md` - Changesets, file uploads, paths
  • `${CLAUDE_SKILL_DIR}/references/security-headers.md` - CSP, CSRF, rate limiting, headers
  • `${CLAUDE_SKILL_DIR}/references/oauth-linking.md` - OAuth account linking, token management
  • `${CLAUDE_SKILL_DIR}/references/rate-limiting.md` - Composite key strategies, Hammer patterns
  • `${CLAUDE_SKILL_DIR}/references/advanced-patterns.md` - SSRF prevention, secrets management, supply chain
Read more
@oliver-kriska
Ships withclaude-elixir-phoenix

Docs: phxagents.dev -- install guides per runtime, the runtime compatibility matrix, all 26 Iron Laws, and a browsable skill and agent catalog. Claude Code is great.

574106 skills37 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
574
Star history of oliver-kriska/claude-elixir-phoenix on GitHub, a chart by star-history.com

Other skills on claude-elixir-phoenix.

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills12d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc13d293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react3d252k
@facebook@facebookInstall Skill

Questions about security.

Which coding agents can use security?
security installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.