Claude Skill

bitrix-security

CSRF, XSS, SQLi, SSRF, JWT/JWK, access rights, encryption. Use when handling input or auditing security.

LLM Mart · 0 points · 10 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download bxmaximum-bitrix-framework-skills-skills_bitrix-security-66c40e0.zip · 5 KB
Part of bxmaximum/bitrix-framework-skills — 38 skills

Install

skills CLI npx skills add https://github.com/bxmaximum/bitrix-framework-skills/tree/main/skills/bitrix-security
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install bxmaximum-bitrix-framework-skills@llmmart
Git git clone https://github.com/bxmaximum/bitrix-framework-skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole bxmaximum/bitrix-framework-skills collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Security in Bitrix

Baseline: main 23.0+. Features newer than baseline are marked Since.

Progressive disclosure: open only the rule files that match the task. Do not read every rules/*.md.

How to use

  1. Identify the layer the task touches.
  2. Open the matching rules/*.md below.
  3. Prefer framework-native Bitrix patterns over custom abstractions.

Choose a rule file

When to read rules/csrf-xss.md

Read rules/csrf-xss.md (CSRF and XSS) when the task involves:

  • CSRF
  • XSS and HTML Sanitization
  • CSRF Details

When to read rules/sql-ssrf.md

Read rules/sql-ssrf.md (SQL injection and SSRF) when the task involves:

  • SSRF
  • SQL Injections

When to read rules/jwt-crypto-access.md

Read rules/jwt-crypto-access.md (JWT, crypto, access, cookies) when the task involves:

  • JWT / JWK
  • Access Rights
  • #[ActionAccess] / AccessCheckControllerInterface
  • Secure Cookies
  • Value Encryption
  • Miscellaneous
  • Checklist

Checklist

  • Opened only the rule file(s) needed for this task.
  • Followed DI / /local/ / security canons from AGENTS.md.
Files (bitrix-framework-skills)
  • rules
    • csrf-xss.md 1.8 KB
      # CSRF and XSS
      
      ## CSRF
      
      ### Form/AJAX Protection
      
      - `Bitrix\Main\Engine\ActionFilter\Csrf` is in the default prefilters for controllers, but `listAllowedScopes()` limits it to **`Controller::SCOPE_AJAX` only**. It does **not** run for REST/`SCOPE_REST` (or other scopes) unless you add an equivalent check yourself.
      - In HTML forms:
      
          ```php
          <?= bitrix_sessid_post() ?> <!-- <input type="hidden" name="sessid" value="..."> -->
          ```
      
      - In `fetch` / AJAX (`runAction`) requests: `X-Bitrix-Csrf-Token: <bitrix_sessid()>` header (or `sessid` in the body).
      - Manual check (if writing a handler directly): `if (!check_bitrix_sessid()) { die('Invalid sessid'); }`.
      
      ### When Sessions are Read-only
      
      If `CloseSession` is enabled (via filter), the CSRF token behaves as usual — the kernel reads it from the request rather than the session.
      
      ### Antipatterns
      
      - A `GET` endpoint that changes state without a CSRF token and checks.
      - Custom `sessid` field in a form without `bitrix_sessid_post()`.
      
      ## XSS and HTML Sanitization
      
      - Output everything via `htmlspecialcharsbx($value)`.
      - In templates — `<?= htmlspecialcharsbx($item['TITLE']) ?>`.
      - For HTML content from users, use `\Bitrix\Main\Text\HtmlFilter` or `CBXSanitizer`:
      
      ```php
      $sanitizer = new \CBXSanitizer();
      $sanitizer->SetLevel(\CBXSanitizer::SECURE_LEVEL_HIGH); // or MEDIUM, LOW
      $safeHtml = $sanitizer->SanitizeHtml($userHtml);
      ```
      
      - Pass JS data via `\Bitrix\Main\Web\Json::encode($data)` instead of direct concatenation.
      - `arResult` in a component template is not escaped by default — escape it yourself.
      
      ## CSRF Details
      
      - `bitrix_sessid_get()` / `bitrix_sessid()` — get token for JS/AJAX headers.
      - ActionFilter `Csrf` → only `SCOPE_AJAX`; REST and custom scopes need their own CSRF/auth strategy.
      - Cookie `SameSite` settings affect CSRF protection — configure in `crypto` / cookie settings.
      
    • jwt-crypto-access.md 5.5 KB
      # JWT, crypto, access, cookies
      
      ## JWT / JWK
      
      Prefer framework-native `Bitrix\Main\Web\JWT` and `Bitrix\Main\Web\JWK` over hand-rolled `header.payload.signature` or local `base64UrlEncode` helpers.
      
      Rules:
      
      - Issue with `JWT::encode()`; verify with `JWT::decode($token, $key, $allowedAlgs)` — **always** pass an algorithm allowlist; never trust `alg` from the token header alone.
      - Always set `exp` and `iat` (and other claims your contract needs). Payload must be JSON-safe scalars/arrays — not complex objects.
      - Secrets / private keys: `.settings_extra.php` or env — not git-tracked `.settings.php`.
      - JOSE unpadded Base64 URL-safe: `JWT::urlsafeB64Encode()` / `urlsafeB64Decode()` — not generic `base64_*` and not for arbitrary MIME blobs.
      - RSA public keys from JWKS: `JWK::parseKeySet()` / `JWK::parseKey()`, then `JWT::decode()`. `JWK` is a public-key helper, not a full key-management API (no private-key constructor for every `kty`).
      - When verifying with a key set that uses `kid`, pass the keyed set from `parseKeySet` into `decode` — do not reimplement key selection.
      
      ```php
      use Bitrix\Main\Web\JWT;
      use Bitrix\Main\Web\JWK;
      
      $token = JWT::encode([
          'sub' => $userId,
          'iat' => time(),
          'exp' => time() + 3600,
      ], $secret, 'HS256');
      
      $decoded = JWT::decode($token, $secret, ['HS256']);
      
      // OpenID / JWKS:
      $keys = JWK::parseKeySet($jwks);
      $decoded = JWT::decode($jwt, $keys, ['RS256']);
      ```
      
      ## Access Rights
      
      ### Basic Checks
      
      ```php
      global $USER;
      
      if (!$USER->IsAuthorized()) { return; }
      if (!$USER->IsAdmin()) { /* ... */ }
      
      if (!$USER->CanDoOperation('edit_own_profile')) { /* ... */ }
      ```
      
      ### Module Permissions
      
      ```php
      $module = 'vendor.blog';
      $rights = \CMain::GetUserRight($module, $USER->GetUserGroupArray());
      if ($rights < 'W') { /* ... */ }
      ```
      
      ### Controller Checks
      
      Prefer kernel filters over globals:
      
      - `ActionFilter\Authentication` for “must be logged in”.
      - `#[ActionAccess]` + `AccessCheckControllerInterface` when the module has an `access` controller (`AccessibleController` / `BaseAccessController`). Details: skill `bitrix-controllers` → `rules/filters.md`.
      - Otherwise a small `ActionFilter\Base` — do **not** copy `$USER` checks into every action.
      
      ```php
      use Bitrix\Main\Engine\ActionFilter\Attribute\Access\ActionAccess;
      use Bitrix\Main\Engine\Contract\AccessCheckControllerInterface;
      
      #[ActionAccess(action: 'post_edit', strategyArgs: ['itemIdRequestKey' => 'id'])]
      public function updateAction(int $id): array { /* ... */ }
      ```
      
      Custom filter example (only when there is no access controller):
      
      ```php
      final class RequireRole extends \Bitrix\Main\Engine\ActionFilter\Base
      {
          public function __construct(private readonly string $role) { parent::__construct(); }
      
          public function onBeforeAction(\Bitrix\Main\Event $event)
          {
              $user = \Bitrix\Main\Engine\CurrentUser::get();
              if (!$user->getId() || !in_array($this->role, $user->getUserGroups(), true))
              {
                  $this->errorCollection->add([new \Bitrix\Main\Error('Forbidden', 'ACCESS_DENIED')]);
                  return new \Bitrix\Main\EventResult(\Bitrix\Main\EventResult::ERROR, null, null, $this);
              }
              return null;
          }
      }
      ```
      
      ### `access` Module
      
      For complex ACL — use `access` module, roles, and permission providers (`Access\Role`, `Access\AccessibleItem`).
      
      ## Secure Cookies
      
      ```php
      $response = \Bitrix\Main\Context::getCurrent()->getResponse();
      $cookie = new \Bitrix\Main\Web\Cookie('VENDOR_TOKEN', $token, time() + 86400);
      $cookie->setHttpOnly(true);
      $cookie->setSecure(true);
      $cookie->setSpread(\Bitrix\Main\Web\Cookie::SPREAD_DOMAIN); // if needed for all subdomains
      $response->addCookie($cookie);
      ```
      
      Use `HttpOnly` + `Secure` + `SameSite=Lax/Strict`. Do not put access tokens in `localStorage`.
      
      ## Value Encryption
      
      - `CryptoField('SECRET')` — tablet field, encrypted transparently.
      - `SecretField('TOKEN')` — not returned on `select = '*'`.
      - Custom encryption: `Bitrix\Main\Security\Cipher`.
      
      ## Miscellaneous
      
      - **Proactive protection** (`proactive` firewall) — scans suspicious request parameters; do not disable without reason.
      - **Two-factor authentication** — enabled for admins by default; keep it.
      - **Captcha** — `\Bitrix\Main\Captcha` / `CCaptcha` for public forms.
      - **Frame protection** — `X-Frame-Options` / CSP headers via kernel settings.
      - **Access control module** (`access`) — roles, `Access\Role`, `Access\AccessibleItem` for complex ACL.
      - **`crypto` section** in `.settings.php` — encryption keys for cookies and `CryptoField`.
      - Store secrets in `.settings_extra.php` and environment variables, **not** in `.settings.php` under git.
      
      ## Checklist
      
      - [ ] AJAX controller actions rely on `Csrf` (`SCOPE_AJAX`); REST/other scopes have an explicit CSRF/auth check.
      - [ ] External URLs from user input use `HttpClient` with timeouts and `privateIp => false` (plus host whitelist where possible).
      - [ ] In ORM queries, field names and operators are taken from a whitelist, not from the request.
      - [ ] There is no concatenation with user input in `SqlExpression`/`ExpressionField`/`runtime`.
      - [ ] In templates, everything coming from the user is via `htmlspecialcharsbx`.
      - [ ] Administrative actions check `$USER->IsAdmin()` or specific `CanDoOperation`; controller ACL prefers `#[ActionAccess]` when the module has an access controller.
      - [ ] Cookies with tokens are `HttpOnly`, `Secure`, `SameSite`.
      - [ ] JWT uses `JWT::encode`/`decode` with an explicit algorithm allowlist; JWKS via `JWK::parseKeySet`.
      - [ ] Secrets are not committed; access to `.settings_extra.php` is restricted.
      
    • sql-ssrf.md 2.4 KB
      # SQL injection and SSRF
      
      ## SSRF
      
      - Do not access URLs from user input directly: `file_get_contents($url)`, `curl` with user hosts.
      - Use `Bitrix\Main\Web\HttpClient` with timeouts and **`privateIp => false`** for user-controlled URLs:
      
          ```php
          $client = new \Bitrix\Main\Web\HttpClient([
              'socketTimeout' => 5,
              'streamTimeout' => 10,
              'redirect' => false,
              'disableSslVerification' => false,
              // Default privateIp is TRUE (private IPs allowed). For SSRF protection:
              'privateIp' => false,
          ]);
          ```
      
      - `privateIp` default **`true`** = private/link-local IPs **allowed**. Set `false` to block `127.0.0.1`, `169.254.*`, `10.*`, `192.168.*`, etc.
      - Also whitelist schemes/hosts where possible; for user-provided webhooks — validate host/scheme/port, sign requests with a secret.
      
      ## SQL Injections
      
      ### Raw SQL (Old Kernel)
      
      ```php
      $conn = \Bitrix\Main\Application::getConnection();
      $helper = $conn->getSqlHelper();
      
      $id = (int)$userInput; // for integers — forced casting
      $login = $helper->forSql($userLogin); // string escaping
      
      $conn->queryExecute("UPDATE b_user SET LOGIN = '{$login}' WHERE ID = {$id}");
      ```
      
      For bulk inserts/updates:
      
      ```php
      [$insertFields, $insertValues] = $helper->prepareInsert('b_user', $fields);
      $conn->queryExecute("INSERT INTO b_user ({$insertFields}) VALUES ({$insertValues})");
      
      $update = $helper->prepareUpdate('b_user', $fields);
      $conn->queryExecute("UPDATE b_user SET {$update[0]} WHERE ID = {$id}", $update[1]);
      ```
      
      ### ORM Queries — Can Also Be Vulnerable
      
      Dangerous spots in `getList`/`query()`:
      
      - `select` and `order` — field names **are not escaped**. Never put a "field name from request" there without a whitelist:
      
          ```php
          $allowedOrder = ['ID', 'CREATED_AT', 'TITLE'];
          $order = in_array(strtoupper($userOrder), $allowedOrder, true) ? strtoupper($userOrder) : 'ID';
      
          PostTable::getList(['order' => [$order => 'DESC']]);
          ```
      
      - `filter` — values are parameterized, but **keys** (field names with `=`, `>`, etc. prefixes) — are not. Also whitelist.
      - `SqlExpression` and `ExpressionField` — the second argument is substituted as is. Never build it from user input:
      
          ```php
          // DANGEROUS:
          new \Bitrix\Main\DB\SqlExpression("IF({$userField} = 1, 'a', 'b')");
      
          // SAFE:
          new \Bitrix\Main\DB\SqlExpression('IF(?# = 1, "a", "b")', $userField);
          ```
      
      - `runtime` fields — same rules.
      
  • SKILL.md 1.2 KB
    ---
    name: bitrix-security
    description: CSRF, XSS, SQLi, SSRF, JWT/JWK, access rights, encryption. Use when handling input or auditing security.
    ---
    
    # Security in Bitrix
    
    Baseline: **main 23.0+**. Features newer than baseline are marked **Since**.
    
    Progressive disclosure: open **only** the rule files that match the task. Do not read every `rules/*.md`.
    
    ## How to use
    
    1. Identify the layer the task touches.
    2. Open the matching `rules/*.md` below.
    3. Prefer framework-native Bitrix patterns over custom abstractions.
    
    
    ## Choose a rule file
    
    ### When to read `rules/csrf-xss.md`
    
    Read `rules/csrf-xss.md` (`CSRF and XSS`) when the task involves:
    
    - CSRF
    - XSS and HTML Sanitization
    - CSRF Details
    
    ### When to read `rules/sql-ssrf.md`
    
    Read `rules/sql-ssrf.md` (`SQL injection and SSRF`) when the task involves:
    
    - SSRF
    - SQL Injections
    
    ### When to read `rules/jwt-crypto-access.md`
    
    Read `rules/jwt-crypto-access.md` (`JWT, crypto, access, cookies`) when the task involves:
    
    - JWT / JWK
    - Access Rights
    - `#[ActionAccess]` / `AccessCheckControllerInterface`
    - Secure Cookies
    - Value Encryption
    - Miscellaneous
    - Checklist
    
    ## Checklist
    
    - [ ] Opened only the rule file(s) needed for this task.
    - [ ] Followed DI / `/local/` / security canons from `AGENTS.md`.
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related