本文へ移動
cccskills
無料GitHub で公開

owasp-asvs

OWASP ASVS v5.0 security verification skill with Drupal 11 mappings. Use when performing security code reviews, implementing security requirements, or verifying security compliance in Drupal projects.

インストール方法を見る

含まれるファイル(1)

  • SKILL.md15.9 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

ASVS Security Verification Skill

Reference: OWASP ASVS v5.0.0 — cross-reference IDs against https://github.com/OWASP/ASVS for the authoritative source.

When This Activates

  • Performing security code reviews
  • Implementing security features
  • Responding to security review findings
  • Security compliance verification

ASVS Requirements Checklist

V1 — Encoding and Sanitization (Critical)

IDRequirementDrupal Validation
V1.1.1Output encoding for HTTP/HTML contextTwig auto-escape or #plain_text
V1.1.2Dynamic URL building with encodingUrl::fromRoute(), never string concat
V1.1.3JavaScript/JSON encodingJson::encode() before output
V1.1.4SQL injection preventionParameterized queries only
V1.1.5OS command injection preventionAvoid shell_exec, exec, system
V1.1.6LDAP injection preventionUse parameterized LDAP queries
V1.1.7Regex metacharacter escapingpreg_quote() on user input
V1.2.1HTML sanitizationXss::filter() or Xss::filterAdmin()
V1.2.2No eval() with user inputAvoid eval(), use Json::decode()
V1.2.3SSRF preventionValidate URLs against explicit allowlist

V2 — Validation

IDRequirementDrupal Validation
V2.1.1Input validation at serverValidate all user input server-side
V2.1.2Server-side validation onlyNever trust client-only validation
V2.2.1Positive validation (allowlist)Use \Drupal\Component\Utility\Html::escape() for plain text
V2.3.1Anti-automation / rate limitingFlood control or custom rate limit service

V3 — Web Frontend Security

IDRequirementDrupal Validation
V3.1.1Cookie Secure attributeini_set('session.cookie_secure', TRUE)
V3.1.2Cookie SameSite attributesession.cookie_samesite = Lax in settings.php
V3.1.3Cookie HttpOnlysession.cookie_httponly = TRUE
V3.2.1HSTS headerStrict-Transport-Security response header
V3.2.2CORS allowlistValidate Origin; never use wildcard
V3.2.3CSP headerContent-Security-Policy response header
V3.2.4X-Content-Type-Optionsnosniff
V3.2.5Referrer-PolicySet appropriate policy
V3.2.6frame-ancestorsPrevent clickjacking via CSP or X-Frame-Options
V3.3.1CSRF protectionForm API tokens (automatic) or CsrfTokenGenerator for custom endpoints

V4 — API and Web Service

IDRequirementDrupal Validation
V4.1.1Content-Type headerSet correct Content-Type on all responses
V4.1.2HTTP method restrictionsrouting.yml methods: key
V4.1.3HTTP request smugglingProper header parsing; avoid custom HTTP parsing
V4.2.1Authentication on every API endpoint_permission or _custom_access in routing

V5 — File Handling

IDRequirementDrupal Validation
V5.1.1File size limitsupload_max_filesize, managed file field limits
V5.1.2File type validationfile_validate_extensions() + MIME check
V5.2.1No file executionNever serve uploads from a web-accessible path as PHP
V5.2.2Path traversal preventionUse FileSystem::realpath(), validate against allowed dirs

V6 — Authentication

IDRequirementDrupal Validation
V6.1.1Password minimum lengthMinimum 12 chars (Drupal default: 8 — raise it)
V6.1.2Breached password checkIntegrate HaveIBeenPwned API or password_policy module
V6.1.3No restrictive composition rulesAllow all printable characters
V6.1.4Long password supportAllow 64+ characters
V6.2.1Multi-factor authenticationtfa module or SAML/OIDC with MFA
V6.3.1Secrets from secure sourcegetenv() or Key module — never config.get()
V6.3.2No production secret fallbackThrow exception if secret missing in prod

V7 — Session Management

IDRequirementDrupal Validation
V7.1.1Session identifier lengthMinimum 128 bits of entropy
V7.1.2Session identifier randomnessCryptographically random (Drupal core handles this)
V7.1.3Session inactivity timeoutConfigure in settings.php
V7.1.4Session termination on logoutsession_destroy() via AccountInterface::logout()
V7.2.1New session on privilege change\Drupal::service('session')->migrate() on role change
V7.2.2Session token not in URLsEnsure session.use_only_cookies = TRUE

V8 — Authorization

IDRequirementDrupal Validation
V8.1.1Least privilegeGrant minimal roles/permissions
V8.1.2Role-based access controluser.permissions + AccessResult
V8.1.3Access control on every request_permission, _entity_access, or _custom_access
V8.2.1No user/role enumerationReturn identical responses for missing vs forbidden
V8.2.2Sensitive data access loggingWatchdog or event subscriber
V8.3.1Object-level authorizationCheck entity ownership, not just route access

V9 — Communication (TLS/Transport)

IDRequirementDrupal Validation
V9.1.1TLS required for all trafficEnforce HTTPS; redirect HTTP → HTTPS
V9.1.2TLS certificate validityValid cert, no self-signed in production
V9.1.3TLS 1.2+ onlyDisable TLS 1.0/1.1 at server level
V9.2.1No mixed contentServe all assets over HTTPS
V9.3.1Outbound TLS verificationVerify peer cert in \GuzzleHttp\Client calls

V10 — Malicious Code / Supply Chain

IDRequirementDrupal Validation
V10.1.1Dependency integritycomposer.lock committed; use composer audit
V10.1.2No unused dependenciesRegularly prune composer.json
V10.2.1Code review for third-party modulesReview contrib module code before enabling
V10.3.1Integrity verificationUse drupal/core-recommended and check module checksums

V11 — Business Logic

IDRequirementDrupal Validation
V11.1.1Sequential step enforcementEnforce workflow states server-side
V11.1.2Business logic limitsRate limits per user/IP per operation
V11.1.3Transaction handlingUse \Drupal\Core\Database\Connection::startTransaction()

V12 — Configuration

IDRequirementDrupal Validation
V12.1.1Debug mode disabled$settings['twig_debug'] = FALSE in prod
V12.1.2Verbose errors suppressederror_reporting(0) in prod; use logging
V12.1.3Security headers presentHSTS, CSP, X-Content-Type-Options
V12.2.1Remove unused modulesUninstall and remove unused contrib
V12.3.1Protect sensitive config files.htaccess on sites/default/, settings.php read-only

V13 — Data Protection

IDRequirementDrupal Validation
V13.1.1Sensitive data not loggedStrip PII from watchdog/log entries
V13.1.2Sensitive data not in URLsNever pass tokens or PII as query parameters
V13.2.1Data retention policyDefine and enforce data retention in code
V13.3.1Alert on anomaliesEvent subscriber for suspicious patterns

V14 — Cryptography

IDRequirementDrupal Validation
V14.1.1Approved algorithms onlyAES-256, SHA-256+; no MD5/SHA-1 for security
V14.2.1Secure random number generation\Drupal\Component\Utility\Crypt::randomBytes()
V14.3.1Passwords hashed with strong algorithmDrupal's PhpassHashedPassword (or stronger via password_compat)
V14.4.1Secrets not in source codeKey module or environment variables
V14.5.1No hardcoded crypto keysUse Key module; rotate keys on breach

Critical Security Patterns for Drupal

SQL Injection (V1.1.4)

// VULNERABLE
$query = "SELECT * FROM users WHERE name = '" . $name . "'";

// SAFE — Drupal Query Builder
$result = $this->connection->select('users', 'u')
  ->fields('u')
  ->condition('name', $name)
  ->execute();

// SAFE — Placeholder
$result = $this->connection->query(
  'SELECT * FROM {users} WHERE name = :name',
  [':name' => $name]
);

XSS Prevention (V1.2.1)

// VULNERABLE
['#markup' => $user_input]

// SAFE — plain text
['#plain_text' => $user_input]

// SAFE — Twig auto-escape (always prefer)
{{ variable }}

// SAFE — Admin HTML (trusted editors only)
use Drupal\Component\Utility\Xss;
$safe = Xss::filterAdmin($html);

// SAFE — plain text in arbitrary context
use Drupal\Component\Utility\Html;
$safe = Html::escape($user_input);

CORS Configuration (V3.2.2)

// VULNERABLE — wildcard
$response->headers->set('Access-Control-Allow-Origin', '*');

// SAFE — explicit allowlist; only add Credentials header when the
// endpoint actually requires cookie/auth-header sharing
$allowed = $config->get('allowed_origins') ?: [];
$origin = $request->headers->get('Origin', '');
if ($origin && in_array($origin, $allowed, TRUE)) {
  $response->headers->set('Access-Control-Allow-Origin', $origin);
  $response->headers->set('Vary', 'Origin');
  // Only add if this endpoint specifically requires credentialed requests:
  // $response->headers->set('Access-Control-Allow-Credentials', 'true');
}

Authorization — Entity Access (V8.1.3, V8.3.1)

// VULNERABLE — route access only, no object-level check
$node = Node::load($nid);
return $node->get('field_secret')->value;

// SAFE — always check entity access
$node = Node::load($nid);
if (!$node || !$node->access('view')) {
  throw new AccessDeniedHttpException();
}
return $node->get('field_secret')->value;

// SAFE — AccessResult in access checker service
use Drupal\Core\Access\AccessResult;
public function access(AccountInterface $account): AccessResult {
  return AccessResult::allowedIfHasPermission($account, 'view secret content')
    ->cachePerPermissions();
}

CSRF for Custom Endpoints (V3.3.1)

// VULNERABLE — custom route with no CSRF check
public function myAction(Request $request): Response { ... }

// SAFE — Form API handles CSRF automatically; for non-form endpoints:
// In routing.yml add: requirements: { _csrf_token: 'TRUE' }
// Then validate token in controller:
$token = $request->query->get('token');
if (!$this->csrfTokenGenerator->validate($token, 'my-action')) {
  throw new AccessDeniedHttpException();
}

Rate Limiting — Flood Control (V2.3.1)

// Drupal's built-in flood control service
$flood = \Drupal::service('flood');
$identifier = $request->getClientIp();

if (!$flood->isAllowed('my_module.action', $threshold = 10, $window = 3600, $identifier)) {
  throw new TooManyRequestsHttpException(null, 'Rate limit exceeded.');
}

// Register the flood event after processing
$flood->register('my_module.action', $window = 3600, $identifier);

Secret Management (V6.3.1)

// VULNERABLE — stored in config
$secret = $config->get('jwt_secret');

// SAFE — environment variable
$secret = getenv('JWT_SECRET');

// SAFE — Key module (preferred for Drupal)
$key = \Drupal::service('key.repository')->getKey('jwt_secret');
$secret = $key->getKeyValue();

// Always fail hard in production if secret is missing
if ($is_production && empty($secret)) {
  throw new \RuntimeException('JWT secret is required in production.');
}

Security Headers (V3.2.1–V3.2.4)

// In an EventSubscriber on KernelEvents::RESPONSE:
$response->headers->set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
$response->headers->set('X-Content-Type-Options', 'nosniff');
$response->headers->set('Content-Security-Policy', "default-src 'self'; script-src 'self'");
$response->headers->set('Referrer-Policy', 'strict-origin-when-cross-origin');
$response->headers->set('X-Frame-Options', 'SAMEORIGIN');

File Upload Validation (V5.1.2)

// SAFE — validate extension and MIME type
$validators = [
  'file_validate_extensions' => ['pdf jpg png'],
  'file_validate_size'       => [10 * 1024 * 1024], // 10 MB
  'file_validate_image_resolution' => ['2000x2000'],
];
$file = file_save_upload('my_field', $validators, 'private://', FILE_EXISTS_RENAME);
if (!$file) {
  // Upload failed validation
}

Cryptographic Operations (V14.2.1, V14.3.1)

// SAFE — cryptographically secure random bytes
use Drupal\Component\Utility\Crypt;
$token = Crypt::randomBytesBase64(32);

// SAFE — password hashing (Drupal core)
$hashed = \Drupal::service('password')->hash($plain);
$valid  = \Drupal::service('password')->check($plain, $hashed);

// UNSAFE — never use for security-sensitive hashing
$bad = md5($input);
$bad = sha1($input);

Quick Verification Checklist

Before any code is committed:

  • V1.1.4 SQL uses parameterized queries (Query Builder or placeholders)
  • V1.2.1 Output uses #plain_text, Html::escape(), or Twig auto-escape
  • V3.2.2 CORS uses explicit allowlist — no *
  • V3.2.3 CSP header defined and restrictive
  • V3.2.1 HSTS enforced for all HTTPS traffic
  • V3.3.1 CSRF tokens present (Form API or _csrf_token routing requirement)
  • V2.3.1 Rate limiting via flood control on sensitive endpoints
  • V6.3.1 Secrets from Key module or environment — not from config.get()
  • V7.1.4 Session destroyed on logout
  • V8.1.3 Entity access checked on every object load (not just route)
  • V9.1.1 All traffic over TLS; HTTP redirects to HTTPS
  • V10.1.1 composer audit passes; composer.lock committed
  • V12.1.1 Debug/verbose error modes disabled in production
  • V14.1.1 No MD5/SHA-1 for security-sensitive operations

Red Flags

PatternASVSRisk
String concat in SQLV1.1.4SQL injection
#markup with user dataV1.2.1XSS
Access-Control-Allow-Origin: *V3.2.2Cross-origin data leakage
eval() with inputV1.2.2Code injection
config.get() for secretsV6.3.1Credential exposure
No rate limiting on auth/formsV2.3.1Brute force / DoS
Missing CSRF tokenV3.3.1CSRF
No entity access checkV8.3.1Broken object-level auth
MD5/SHA-1 for passwords or tokensV14.1.1Weak cryptography
Uploaded files in public:// without type checkV5.1.2Remote code execution
HTTP-only routes in productionV9.1.1Credential interception
Debug mode / verbose errors in prodV12.1.1Information disclosure

Drupal-Specific Module References

ConcernRecommended Module / Core API
Secrets / key storagedrupal/key + drupal/key_asymmetric
Rate limitingCore Flood service or drupal/rate_limiter
MFAdrupal/tfa
Password policydrupal/password_policy
Security headersdrupal/seckit
SAML / OIDC SSOdrupal/samlauth or drupal/openid_connect
File scanningdrupal/clamav
Security auditdrupal/security_review
Dependency auditcomposer audit (built-in)

References

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Safe deployment workflow for Drupal 10/11 sites: pre-flight checks, backup, the correct update sequence (composer install, database updates, config import, cache rebuild), verification, and rollback plan. Use when deploying to any environment, releasing to production, or when the user asks to "push changes live", "update the server", or run a release. Also use for multisite releases where each site needs its own database update pass.

日本語の概要は準備中です。原文の説明を表示しています。

siva01c/claude-plugins162026年9月26日 更新

Use this skill when authoring or editing Docker Compose files (compose.yaml / docker-compose.yml), running multi-container stacks, or containerizing a Drupal/PHP application — e.g. "set up a local Drupal stack with nginx and MariaDB", "add Redis to my compose file", "why won't my containers start", "split dev and prod compose configuration". Also trigger for compose commands (up, down, logs, exec, watch) and healthcheck/dependency issues between services.

日本語の概要は準備中です。原文の説明を表示しています。

siva01c/claude-plugins162026年9月26日 更新

Use this skill when running local AI models with Docker Model Runner — the `docker model` CLI — e.g. "run an LLM locally with Docker", "pull a model from the ai/ namespace", "connect my app to a local model", "use a local model as backend for the Drupal AI module", or when wiring the `models:` top-level element into a compose.yaml. Covers pulling/running models, OpenAI-compatible endpoints, and Compose integration.

日本語の概要は準備中です。原文の説明を表示しています。

siva01c/claude-plugins162026年9月26日 更新

Use for operational Drupal 11 workflows in DDEV environments, including safe updates, backup-first procedures, and troubleshooting commands.

日本語の概要は準備中です。原文の説明を表示しています。

siva01c/claude-plugins162026年9月26日 更新

Use when creating or extending Drupal 11 custom modules, including scaffolding, service architecture, and dependency injection best practices.

日本語の概要は準備中です。原文の説明を表示しています。

siva01c/claude-plugins162026年9月26日 更新

Use when auditing Drupal 11 custom modules/themes for security issues such as unsafe input handling, XSS risks, SQL injection, and access control gaps.

日本語の概要は準備中です。原文の説明を表示しています。

siva01c/claude-plugins162026年9月26日 更新

siva01c のスキルをすべて見る

このスキルの問題を報告する