Communitygithub.com

laravel-security

Laravel 보안 모범 사례 — 인증, 권한 부여, Eloquent 안전성, CSRF, XSS 방지, API 보안 및 안전한 배포 구성. Laravel 인증, Eloquent 안전성, CSRF, XSS, API 보안 또는 배포 구성을 검토할 때 사용하세요.

laravel-security란 무엇인가요?

이 스킬은 Laravel 애플리케이션의 보안 모범 사례에 대한 포괄적인 가이드를 제공합니다. 인증, 권한 부여, Eloquent ORM 안전성, CSRF 보호, XSS 방지, API 보안, 생산 환경 배포 구성 등 주요 보안 영역을 다룹니다. 개발자가 Laravel 프로젝트에서 일반적인 취약점을 방지하고 안전한 코드를 작성할 수 있도록 구체적인 코드 예제와 설정 방법을 제시합니다. Sanctum, Passport, Jetstream, Breeze와 같은 인증 패키지와 Gate 및 Policy를 통한 권한 부여, Eloquent의 대량 할당 방어, SQL 인젝션 방지, CSRF 토큰 처리, Blade 템플릿에서의 XSS 방지 등 실무에서 바로 적용 가능한 보안 팁을 포함하고 있습니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/laravel-security

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

Laravel 보안 모범 사례

Laravel 애플리케이션을 일반적인 취약점으로부터 보호하기 위한 포괄적인 보안 가이드입니다.

활성화 시점

  • Laravel 인증 및 권한 부여 설정 (Sanctum, Passport, Jetstream, Breeze)
  • 사용자 역할, 권한 및 정책 구현
  • 프로덕션 보안 설정 및 환경 변수 구성
  • Laravel 애플리케이션의 보안 취약점 검토
  • Laravel 애플리케이션을 프로덕션에 배포
  • 안전한 Eloquent 쿼리 및 마이그레이션 작성

프로덕션 구성

필수 프로덕션 설정

// config/app.php
'env' => env('APP_ENV', 'production'),
'debug' => (bool) env('APP_DEBUG', false), // 중요: 프로덕션에서는 절대 true로 설정하지 마세요
'key' => env('APP_KEY'), // 반드시 설정해야 함: php artisan key:generate

// config/session.php
'secure' => env('SESSION_SECURE_COOKIE', true),
'http_only' => true,
'same_site' => 'lax',

// 부트 시 APP_KEY 확인
// bootstrap/app.php 또는 서비스 프로바이더
if (empty(config('app.key'))) {
    throw new RuntimeException('APP_KEY가 설정되지 않았습니다. 실행: php artisan key:generate');
}

환경 파일 보안

# 절대 .env를 버전 관리에 커밋하지 마세요
# .gitignore는 기본적으로 .env를 포함합니다

# 대신 .env.example을 자리 표시자와 함께 사용하세요
DB_PASSWORD=
APP_KEY=
SANCTUM_TOKEN_PREFIX=

# 부트 시 필수 변수 검증
// AppServiceProvider::boot()에서
$requiredKeys = ['app.key', 'database.connections.mysql.database', 'database.connections.mysql.username'];
foreach ($requiredKeys as $key) {
    if (empty(config($key))) {
        throw new RuntimeException("필수 구성 키 누락: {$key}");
    }
}

HTTPS 강제 적용

// AppServiceProvider::boot() 또는 미들웨어
if (app()->environment('production')) {
    URL::forceScheme('https');
    request()->server->set('HTTPS', 'on');
}

// config/app.php의 신뢰할 수 있는 프록시 (로드 밸런서)
// 특정 IP 범위 사용 — *는 모든 것을 신뢰하여 X-Forwarded-* 스푸핑 허용
// AWS: '10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16'
'trusted_proxies' => ['10.0.0.0/8', '172.16.0.0/12'],

// 미들웨어를 통해 프로덕션에서 HTTPS 강제 적용
// app/Http/Middleware/ForceHttps.php
public function handle($request, Closure $next)
{
    if (!$request->secure() && app()->environment('production')) {
        return redirect()->secure($request->getRequestUri());
    }
    return $next($request);
}

인증

Sanctum (API 토큰 인증)

// config/sanctum.php
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
    '%s%s',
    'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
    env('APP_URL') ? ',' . parse_url(env('APP_URL'), PHP_URL_HOST) : ''
)));

'expiration' => 60 * 24, // 토큰 만료 시간 (분 단위, null = 만료 없음)
'token_prefix' => env('SANCTUM_TOKEN_PREFIX', ''),

// 권한(abilities)이 있는 토큰 발급
$token = $user->createToken('api-token', ['read', 'write'])->plainTextToken;

// 라우트에서 권한 검증
Route::middleware('auth:sanctum')->group(function () {
    Route::get('/orders', function () {
        // 사용자에게 'read' 권한이 있어야 함
        abort_unless(Auth::user()->tokenCan('read'), 403);
        // ...
    })->middleware('abilities:read');

    Route::post('/orders', function () {
        // 사용자에게 'write' 권한이 있어야 함
        abort_unless(Auth::user()->tokenCan('write'), 403);
        // ...
    })->middleware('abilities:write');
});

비밀번호 보안

// config/hashing.php
// 기본값은 bcrypt입니다. Argon2id가 더 강력합니다.
'bcrypt' => [
    'rounds' => env('BCRYPT_ROUNDS', 12), // 더 강력한 해싱을 위해 증가
],

'argon' => [
    'memory' => 65536,
    'threads' => 4,
    'time' => 4,
],

// RegisterRequest에서 비밀번호 검증
public function rules(): array
{
    return [
        'password' => [
            'required',
            'confirmed',
            Password::min(12)
                ->letters()
                ->mixedCase()
                ->numbers()
                ->symbols()
                ->uncompromised(), // haveibeenpwned 확인
        ],
    ];
}

// 로그인 시도 속도 제한
// App\Http\Controllers\Auth\AuthenticatedSessionController
protected function authenticated(Request $request, $user)
{
    if ($user->wasRecentlyLockedOut()) {
        // 사용자에게 의심스러운 로그인 알림
        $user->notify(new SuspiciousLoginNotification($request->ip()));
    }
}

세션 관리

// config/session.php
'driver' => env('SESSION_DRIVER', 'database'), // database/redis > file
'lifetime' => env('SESSION_LIFETIME', 120),
'expire_on_close' => env('SESSION_EXPIRE_ON_CLOSE', false),
'encrypt' => env('SESSION_ENCRYPT', false),

// 로그인 시 세션 재생성
// App\Http\Controllers\Auth\AuthenticatedSessionController
public function store(LoginRequest $request): RedirectResponse
{
    $request->authenticate();
    $request->session()->regenerate(); // 중요: 세션 고정 방지
    return redirect()->intended(RouteServiceProvider::HOME);
}

// 로그아웃 시 세션 무효화
public function destroy(Request $request): RedirectResponse
{
    Auth::guard('web')->logout();
    $request->session()->invalidate();
    $request->session()->regenerateToken();
    return redirect('/');
}

권한 부여

게이트(Gates)

// App\Providers\AuthServiceProvider
use App\Models\Post;
use App\Models\User;
use Illuminate\Support\Facades\Gate;

public function boot(): void
{
    Gate::define('update-post', function (User $user, Post $post): bool {
        return $user->id === $post->user_id;
    });

    Gate::define('publish-post', function (User $user): bool {
        return $user->role === 'editor' || $user->role === 'admin';
    });

    // before()를 사용한 슈퍼 관리자 재정의
    Gate::before(function (User $user, string $ability): ?bool {
        if ($user->role === 'super-admin') {
            return true; // 모든 권한 부여
        }
        return null; // 일반 검증으로 대체
    });
}

// 컨트롤러에서 사용
public function update(Request $request, Post $post): RedirectResponse
{
    Gate::authorize('update-post', $post);
    // 또는: $this->authorize('update-post', $post);
    // 또는: abort_unless(Auth::user()->can('update-post', $post), 403);
    // ...
}

정책(Policies)

// App\Policies\PostPolicy
class PostPolicy
{
    use HandlesAuthorization;

    public function viewAny(?User $user): bool
    {
        return true; // 공개 목록
    }

    public function view(?User $user, Post $post): bool
    {
        return $post->is_published || ($user && $user->id === $post->user_id);
    }

    public function create(User $user): bool
    {
        return $user->hasVerifiedEmail(); // 이메일 인증 필수
    }

    public function update(User $user, Post $post): bool
    {
        return $user->id === $post->user_id;
    }

    public function delete(User $user, Post $post): bool
    {
        return $user->id === $post->user_id && $post->created_at->diffInDays(now()) <= 30;
    }

    public function restore(User $user, Post $post): bool
    {
        return $user->role === 'admin';
    }

    public function forceDelete(User $user, Post $post): bool
    {
        return $user->role === 'super-admin';
    }
}

// AuthServiceProvider에 등록
protected $policies = [
    Post::class => PostPolicy::class,
];

// 컨트롤러 사용
public function show(Post $post): View
{
    $this->authorize('view', $post);
    return view('posts.show', compact('post'));
}

// Blade 사용
@can('update', $post)
    <a href="{{ route('posts.edit', $post) }}">Edit</a>
@endcan

@cannot('update', $post)
    <span>You cannot edit this post</span>
@endcannot

미들웨어 권한 부여

// 라우트에서 미들웨어 사용
Route::put('/posts/{post}', [PostController::class, 'update'])
    ->middleware('can:update,post');

Route::get('/posts/create', [PostController::class, 'create'])
    ->middleware('can:create,App\Models\Post');

// 사용자 정의 권한 부여 미들웨어
// app/Http/Middleware/CheckRole.php
class CheckRole
{
    public function handle(Request $request, Closure $next, string $role): mixed
    {
        if (!$request->user() || $request->user()->role !== $role) {
            abort(403, '권한 없음. 이 영역은 역할이 필요합니다: ' . $role);
        }
        return $next($request);
    }
}

// Kernel에 등록
protected $routeMiddleware = [
    'role' => \App\Http\Middleware\CheckRole::class,
];

// 라우트 사용
Route::middleware(['auth', 'role:admin'])->group(function () {
    Route::get('/admin', [AdminController::class, 'index']);
});

Eloquent 보안

대량 할당 보호

// 나쁜 예: $guarded = []는 모든 컬럼을 대량 할당 가능하게 함
// 프로덕션에서 절대 $guarded = []를 사용하지 마세요

// 좋은 예: fillable 속성 허용 목록 설정
final class User extends Authenticatable
{
    protected $fillable = [
        'name',
        'email',
        'phone',
        'avatar',
    ];
    // 절대 'role', 'is_admin', 'is_verified'를 여기에 추가하지 마세요
}

// 좋은 예: 요청에서 채울 수 있는 필드를 명시적으로 제어
public function store(StoreUserRequest $request): RedirectResponse
{
    $user = User::create($request->safe()->only([
        'name', 'email', 'phone', 'avatar'
    ]));
    // $request->safe()는 검증된 데이터만 사용
    // $request->only()는 검증 규칙 없이 자체적으로 안전하지 않음
}

// 나쁜 예: 요청 데이터로 직접 사용자 생성
User::create($request->all()); // 대량 할당에 취약!

// 더 좋은 예: 생성을 위해 DTO 사용
$user = User::create($request->validated()); // 검증된 필드만

SQL 인젝션 방지

// 좋은 예: Eloquent는 자동으로 쿼리를 파라미터화
User::where('email', $userInput)->first();
User::whereRaw('email = ?', [$userInput])->first();

// 좋은 예: Query Builder도 파라미터화
DB::table('users')->where('email', $userInput)->first();
DB::select('SELECT * FROM users WHERE email = ?', [$userInput]);

// 나쁜 예: 원시 문자열 보간
DB::select("SELECT * FROM users WHERE email = '{$userInput}'"); // 취약!
User::whereRaw("email = '{$userInput}'")->first(); // 취약!

// 나쁜 예: 이스케이프되지 않은 입력과 함께 whereRaw/orderByRaw 사용
User::orderByRaw($userInput); // 취약!
User::groupByRaw($userInput); // 취약!

// 나쁜 예: 연결과 함께 DB::statement 사용
DB::statement("INSERT INTO users (email) VALUES ('{$userInput}')"); // 취약!

속성 캐스팅

final class User extends Authenticatable
{
    protected $casts = [
        'email_verified_at' => 'datetime',
        'is_admin' => 'boolean', // boolean으로 캐스팅하면 문자열 인젝션 방지
        'settings' => 'array', // 자동으로 json_encode/json_decode
        'metadata' => 'encrypted:array', // Laravel 11+ 암호화 캐스팅
        'password' => 'hashed', // Laravel 10+ 설정 시 자동 해싱
    ];
}

모델 보안

final class User extends Authenticatable
{
    // JSON/API 응답에서 민감한 속성 숨기기
    protected $hidden = [
        'password',
        'remember_token',
        'two_factor_secret',
        'two_factor_recovery_codes',
    ];

    // 안전한 계산된 속성만 추가
    protected $appends = ['full_name']; // 안전
    // 절대 민감한 계산 데이터를 추가하지 마세요
}

final class Post extends Model
{
    // 소프트 삭제된 레코드를 필터링하는 글로벌 스코프
    use SoftDeletes;

    // 지연 로딩을 제한하여 N+1 방지 (선택적 엄격 모드)
    // AppServiceProvider::boot()
    // Model::preventLazyLoading(!app()->isProduction());
}

CSRF 보호

기본 보호

// Laravel CSRF는 VerifyCsrfToken 미들웨어를 통해 기본적으로 활성화
// app/Http/Kernel.php (protected $middlewareGroups['web'])

// 모든 POST/PUT/PATCH/DELETE 양식은 @csrf를 포함해야 함
<form method="POST" action="/posts">
    @csrf
    <input type="text" name="title">
    <button type="submit">Create</button>
</form>

라우트 제외 (주의해서)

// app/Http/Middleware/VerifyCsrfToken.php
class VerifyCsrfToken extends Middleware
{
    // 외부 CSRF 보호(웹훅 등)가 있는 라우트만 제외
    protected $except = [
        'stripe/*', // Stripe 웹훅은 자체 서명 검증 사용
        // 포괄적인 'api/*'는 피하세요 — 상태 저장 Sanctum 라우트에는 CSRF가 필요합니다.
        // 특정 상태 비저장 웹훅/엔드포인트 라우트만 제외하세요.
    ];
}

JavaScript와 CSRF

<meta name="csrf-token" content="{{ csrf_token() }}">

<script>
// Axios 예제 (Laravel은 Axios를 기본 제공)
axios.defaults.headers.common['X-CSRF-TOKEN'] = document.querySelector(
    'meta[name="csrf-token"]'
).getAttribute('content');

// Fetch 예제
fetch('/posts', {
    method: 'POST',
    headers: {
        'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
        'Content-Type': 'application/json',
    },
    body: JSON.stringify(data),
});
</script>

XSS 방지

Blade 템플릿 보안

{{-- 안전: Blade에 의해 자동 이스케이프 처리 --}}
{{ $userInput }}

{{-- 위험: 원시 출력 — 사용자 입력에 절대 사용하지 마세요 --}}
{!! $userInput !!}

{{-- 안전: {!! !!}는 사용자가 제어하는 신뢰할 수 있는 콘텐츠에만 사용 --}}
{!! $trustedHtmlFromYourServer !!}

{{-- 좋은 예: 특정 이스케이프 지시문 사용 --}}
@js($data) {{-- JavaScript용 JSON 인코드 --}}
@json($data) {{-- 템플릿에서 JSON 인코드 --}}

{{-- 나쁜 예: 원시 HTML에 직접 사용자 입력 --}}
<div>{!! $user->bio !!}</div> {{-- 사용자가 bio를 제공하는 경우 취약 --}}

안전한 HTML 처리

// 일부 HTML을 허용해야 하는 경우 허용 목록 접근 방식 사용
use HTMLPurifier; // 필요: composer require ezyang/htmlpurifier

public function sanitizeHtml(string $dirty): string
{
    $config = \HTMLPurifier_Config::createDefault();
    $config->set('HTML.Allowed', 'p,b,i,a[href],ul,ol,li,br');
    $config->set('URI.AllowedSchemes', ['http', 'https', 'mailto']);
    $purifier = new \HTMLPurifier($config);
    return $purifier->purify($dirty);
}

// Blade에서:
<div>{!! $sanitizedHtml !!}</div>

// Laravel의 Str::markdown 사용 (신뢰할 수 있는 입력에만)
use Illuminate\Support\Str;
$html = Str::markdown($userInput); // XSS를 완전히 방지하지는 않음

Content Security Policy (CSP)

// app/Http/Middleware/ContentSecurityPolicy.php
namespace App\Http\Middleware;

use Closure;

class ContentSecurityPolicy
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);

        $response->headers->set('Content-Security-Policy',
            "default-src 'self'; " .
            "script-src 'self' 'nonce-" . base64_encode(random_bytes(16)) . "'; " .
            "style-src 'self' 'unsafe-inline'; " .
            "img-src 'self' data: https:; " .
            "font-src 'self'; " .
            "frame-src 'none'; " .
            "object-src 'none'; " .
            "base-uri 'self'; " .
            "form-action 'self'"
        );

        return $response;
    }
}

// Kernel에 등록
// app/Http/Kernel.php
protected $middlewareGroups = [
    'web' => [
        // ...
        \App\Http\Middleware\ContentSecurityPolicy::class,
    ],
];

// Blade에서 nonce 사용
<script nonce="{{ $cspNonce }}">
    // JavaScript 코드
</script>

API 보안

속도 제한

// app/Providers/RouteServiceProvider.php
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;

protected function configureRateLimiting(): void
{
    // API 라우트 속도 제한
    RateLimiter::for('api', function (Request $request) {
        return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
    });

    // 로그인 시도 속도 제한
    RateLimiter::for('login', function (Request $request) {
        return Limit::perMinute(5)->by($request->input('email') . '|' . $request->ip());
    });
}

// routes/api.php에서 사용
Route::middleware(['auth:sanctum', 'throttle:api'])->group(function () {
    Route::get('/user', function (Request $request) {
        return $request->user();
    });
});

API 입력 검증

// app/Http/Requests/Api/StorePostRequest.php
class StorePostRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true; // 미들웨어가 인증 처리
    }

    public function rules(): array
    {
        return [
            'title' => ['required', 'string', 'max:255'],
            'body' => ['required', 'string'],
            'category_id' => ['required', 'exists:categories,id'],
            'tags' => ['array'],
            'tags.*' => ['exists:tags,id', 'distinct'],
        ];
    }

    // 실패 시 JSON 오류 반환
    protected function failedValidation(Validator $validator)
    {
        throw new HttpResponseException(response()->json([
            'message' => '검증 실패',
            'errors' => $validator->errors(),
        ], 422));
    }
}

// 컨트롤러 사용
public function store(StorePostRequest $request): JsonResponse
{
    $post = Post::create($request->validated());
    return response()->json($post, 201);
}

API 응답 보안

// 헤더를 통한 정보 노출 방지
// AppServiceProvider::boot() 또는 미들웨어
public function boot(): void
{
    // 애플리케이션 버전 숨기기
    header_remove('X-Powered-By');

    // JSON 응답에 대한 CORS 헤더
    // config/cors.php에서 구성 (Laravel 7+)
}

// 안전한 API 리소스 응답
// app/Http/Resources/UserResource.php
class UserResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->email,
            // 민감한 필드 제외: role, is_admin, password 등
            'created_at' => $this->created_at,
            'updated_at' => $this->updated_at,
        ];
    }
}

CORS 구성

// config/cors.php
return [
    'paths' => ['api/*', 'sanctum/csrf-cookie'],
    'allowed_methods' => ['*'],
    'allowed_origins' => [env('FRONTEND_URL', 'http://localhost:3000')],
    'allowed_origins_patterns' => [],
    'allowed_headers' => ['*'],
    'exposed_headers' => ['X-Total-Count', 'X-Page'],
    'max_age' => 0,
    'supports_credentials' => true, // Sanctum 쿠키 기반 인증에 필요
];

프로덕션 배포

파일 권한

# 디렉토리에 올바른 권한 설정
chmod 755 /path/to/laravel
chmod 775 /path/to/laravel/storage
chmod 775 /path/to/laravel/bootstrap/cache

# 소유권 설정 (웹 서버 사용자)
chown -R www-data:www-data /path/to/laravel
# 또는
chown -R $USER:www-data /path/to/laravel

배포 전 체크리스트

# 1. 디버그 모드 비활성화
APP_DEBUG=false

# 2. APP_KEY 설정
php artisan key:generate

# 3. HTTPS 강제 적용 (프록시를 통해 처리하지 않는 경우)
# AppServiceProvider에서 URL::forceScheme('https')

# 4. 캐시 지우기
php artisan config:cache
php artisan route:cache
php artisan view:cache

# 5. 불필요한 서비스 비활성화
php artisan telescope:clear # 개발 환경에서 사용
php artisan horizon:terminate # 프로덕션에서 사용하지 않는 경우

보안 헤더

// app/Http/Middleware/SecurityHeaders.php
class SecurityHeaders
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);

        $response->headers->set('X-Content-Type-Options', 'nosniff');
        $response->headers->set('X-Frame-Options', 'DENY');
        $response->headers->set('X-XSS-Protection', '1; mode=block');
        $response->headers->set('Referrer-Policy', 'strict-origin-when-cross-origin');
        $response->headers->set('Permissions-Policy',
            'camera=(), microphone=(), geolocation=(), interest-cohort=()'
        );

        // CSP는 위에서 별도 미들웨어로 처리

        return $response;
    }
}

// Kernel에 등록
protected $middlewareGroups = [
    'web' => [
        // ...
        \App\Http\Middleware\SecurityHeaders::class,
    ],
];

일반적인 취약점

디버그 모드

// 절대 프로덕션에서 APP_DEBUG=true로 설정하지 마세요
// 민감한 구성 값, 데이터베이스 자격 증명 등을 노출합니다

// .env
APP_DEBUG=false # 프로덕션

// 대신 사용자 정의 오류 처리
// app/Exceptions/Handler.php
public function register(): void
{
    $this->reportable(function (Throwable $e) {
        // 프로덕션에서 오류 기록 (절대 화면에 표시하지 않음)
        Log::error($e->getMessage(), ['trace' => $e->getTraceAsString()]);
    });

    $this->renderable(function (NotFoundHttpException $e, Request $request) {
        if ($request->expectsJson()) {
            return response()->json(['message' => '리소스를 찾을 수 없습니다.'], 404);
        }
        return response()->view('errors.404', [], 404);
    });
}

의존성 보안

# 정기적으로 취약점 스캔
composer audit

# 의존성 업데이트
composer update

# 수정 불가능한 취약점 확인
composer audit --format=json | jq '."advisories" | length'

빠른 참조

영역구성 파일필수 설정
인증config/auth.php, config/sanctum.php적절한 가드, 토큰 만료, HTTPS
권한App\Providers\AuthServiceProviderGate/Policy 정의, 슈퍼 관리자 처리
CSRFapp/Http/Middleware/VerifyCsrfToken.php모든 양식에 @csrf, JavaScript 헤더
XSSBlade 템플릿{{ }} 사용, {!! !!}는 신뢰할 수 있는 콘텐츠에만
APIconfig/cors.php, config/sanctum.phpCORS 구성, 속도 제한, 검증
세션config/session.php보안 쿠키, HTTP 전용, SameSite
데이터베이스config/database.phpSSL 연결, 강력한 비밀번호
로깅config/logging.php프로덕션에서 스택/슬랙/데이터독 사용

보안 검증

# 확인 명령
php artisan about # 구성 확인
php artisan route:list # 노출된 라우트 확인
php artisan config:show database # 데이터베이스 설정 표시

# 보안 감사 명령 (패키지 필요)
composer require --dev beyondcode/laravel-erkennung
php artisan security:check

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

관련 스킬