You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When configuring protected assets via the SS_PROTECTED_ASSETS_PATH environment variable with a relative path (e.g. ../restricted_assets), the path is used as-is without resolving it relative to BASE_PATH. This causes the protected assets directory to end up in an unexpected location because PHP resolves the relative path against its current working directory (cwd), which differs between web requests (public/) and CLI (project root or wherever the command was run from).
The parent class AssetAdapter::findRoot() has logic to handle relative paths (./ → BASE_PATH, ../ → dirname(BASE_PATH)), but ProtectedAssetAdapter::findRoot() bypasses this when the env var is set.
Steps to reproduce
Set SS_PROTECTED_ASSETS_PATH="../restricted_assets" in .env
Upload a file via the CMS
The protected assets directory is created relative to PHP's cwd, not relative to BASE_PATH
Web request: resolves relative to public/ → ends up at project root (public/../restricted_assets)
CLI: resolves relative to wherever the command was run from
Expected behaviour
Relative paths in SS_PROTECTED_ASSETS_PATH should resolve relative to BASE_PATH, consistent with:
The AssetAdapter::findRoot() parent logic (which handles ./ and ../ substitution)
The YAML Injector configuration approach (which passes root through parent::findRoot() and works correctly)
In ProtectedAssetAdapter::findRoot(), when SS_PROTECTED_ASSETS_PATH is set, the method returns the raw env var value without calling parent::findRoot():
protectedfunctionfindRoot($root)
{
$path = Environment::getEnv('SS_PROTECTED_ASSETS_PATH');
if ($path) {
return$path; // ← Returns raw value, bypasses parent's relative path resolution
}
// ...returnparent::findRoot($root); // ← Only reached when env var is NOT set
}
The parent AssetAdapter::findRoot() contains the relative path handling:
When using YAML Injector config (constructor arg), $root is passed through parent::findRoot() and relative paths resolve correctly. Only the env var code path has this issue.
Suggested fix
Pass the env var value through parent::findRoot() instead of returning it directly:
Description
When configuring protected assets via the
SS_PROTECTED_ASSETS_PATHenvironment variable with a relative path (e.g.../restricted_assets), the path is used as-is without resolving it relative toBASE_PATH. This causes the protected assets directory to end up in an unexpected location because PHP resolves the relative path against its current working directory (cwd), which differs between web requests (public/) and CLI (project rootor wherever the command was run from).The parent class
AssetAdapter::findRoot()has logic to handle relative paths (./→BASE_PATH,../→dirname(BASE_PATH)), butProtectedAssetAdapter::findRoot()bypasses this when the env var is set.Steps to reproduce
SS_PROTECTED_ASSETS_PATH="../restricted_assets"in.envcwd, not relative toBASE_PATHpublic/→ ends up at project root (public/../restricted_assets)Expected behaviour
Relative paths in
SS_PROTECTED_ASSETS_PATHshould resolve relative toBASE_PATH, consistent with:AssetAdapter::findRoot()parent logic (which handles./and../substitution)rootthroughparent::findRoot()and works correctly)root: './assets'Cause
In
ProtectedAssetAdapter::findRoot(), whenSS_PROTECTED_ASSETS_PATHis set, the method returns the raw env var value without callingparent::findRoot():The parent
AssetAdapter::findRoot()contains the relative path handling:When using YAML Injector config (constructor arg),
$rootis passed throughparent::findRoot()and relative paths resolve correctly. Only the env var code path has this issue.Suggested fix
Pass the env var value through
parent::findRoot()instead of returning it directly:Workaround
Use an absolute path in
SS_PROTECTED_ASSETS_PATH:Affects
All versions since SS4 (when protected assets were introduced via silverstripe/silverstripe-framework#7710).