🐛 Bug: restrictLayoutsTo check fails when layout path is absolute
In express-hbs/lib/hbs.js, this logic currently fails for valid layout paths if the layout is passed as an absolute path:
if (this.restrictLayoutsTo) {
if (!layoutFile.startsWith(this.restrictLayoutsTo)) {
var err = new Error('Cannot read ' + layoutFile + ' it does not reside in ' + this.restrictLayoutsTo);
return cb(err, null);
}
}
This breaks themes when layouts are loaded by full path (e.g., /var/lib/ghost/content/themes/taste/default) even though they do reside under content/themes/taste.
✅ Proposed Fix
Use path.relative() to properly verify the layout's path is inside the allowed directory:
if (this.restrictLayoutsTo) {
const path = require('path');
const relativePath = path.relative(this.restrictLayoutsTo, layoutFile);
if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
const err = new Error('Cannot read ' + layoutFile + ' it does not reside in ' + this.restrictLayoutsTo);
return cb(err, null);
}
}
This is safer and more reliable than startsWith().
📦 Affected Versions
This occurs when used with Ghost CMS >=5.x that uses express-hbs with absolute paths and restrictLayoutsTo set.
🙋♂️ Maintainer Notes
Happy to submit a PR referencing this issue.
🐛 Bug:
restrictLayoutsTocheck fails when layout path is absoluteIn
express-hbs/lib/hbs.js, this logic currently fails for valid layout paths if the layout is passed as an absolute path:This breaks themes when layouts are loaded by full path (e.g.,
/var/lib/ghost/content/themes/taste/default) even though they do reside undercontent/themes/taste.✅ Proposed Fix
Use
path.relative()to properly verify the layout's path is inside the allowed directory:This is safer and more reliable than
startsWith().📦 Affected Versions
This occurs when used with Ghost CMS >=5.x that uses
express-hbswith absolute paths andrestrictLayoutsToset.🙋♂️ Maintainer Notes
Happy to submit a PR referencing this issue.