
Research
Supply Chain Attack on Axios Pulls Malicious Dependency from npm
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.
A small lightweight but powerful template engine.
Install:npm install small-tpl or yarn add small-tpl
<? 开始标签
?> 结束标签
each 遍历数组
endeach 结束遍历
echo 在JS脚本里输出数据
$data 模板内嵌变量,渲染模板的数据对象
$fn 模板内嵌变量,渲染模板的helper对象
$encodeChars 模板内嵌变量,输出内容时需要编码的字符,默认包含4个字符<、>、"、'
$encode 模板内嵌函数,输出内容时对内容进行编码
$indent 模板内嵌函数,输出内容时对内容保持当前缩进量
$item 模板内嵌变量,遍历数组时指向当前数组元素
$i 模板内嵌变量,遍历数组时指向当前数组元素的下标
$count 模板内嵌变量,遍历数组时指向当前数组的长度
= 在“each”外时输出$data对象的属性,在“each”里时输出$item对象的属性;属性值为null或undefined时输出空字符串
=: 与“=”相似,区别在于会用$encode编码内容
=] 与“=”相似,区别在于会用$indent保持当前缩进量
+ 直接字符串连接整个语句块,不做任何处理
compile(template, [options])
编译模板字符串为渲染函数。
options有3个选项:openTag自定义开始标签;closeTag自定义结束标签;uglify是否去除HTML里无用的空白字符,默认true去除。
setTag(openTag, closeTag)
全局设置开始标签和结束标签。
Hello world
const { compile } = require('small-tpl')
// for pure Object
const render = compile('<?= hello ?>, <?= name ?>!')
render({hello: 'Hello', name: 'girl'})
// => Hello, girl!
// for Array
const render = compile('<?+ $data[0] ?>, <?+ $data[1] ?>!')
render(['Hello', 'girl'])
// => Hello, girl!
标签内可以使用原生JS语法:
<div>
<? if ($data.someProp) { ?>
<h1>哈哈哈</h1>
<? } else { ?>
<i>嘿嘿嘿</i>
<? } ?>
</div>
JS代码内可以使用echo语句,上面的代码等同于:
<div>
<?
if ($data.someProp) {
echo '<h1>哈哈哈</h1>' // 也可以写成 echo('<h1>哈哈哈</h1>')
} else {
echo '<i>嘿嘿嘿</i>'
}
?>
</div>
三目运算:
<h1><?+ ($data.someProp ? '哈哈哈' : '嘿嘿嘿') ?></h1>
遍历数组:
<h1><?= title ?></h1> <!-- 输出 $data.title -->
<ul>
<? each $data.someList ?>
<li>
<?= title ?> <!-- 输出 someList 里每一项的 title,即 $item.title -->
<? if ($item.subTitle) { ?> <!-- $item 指向 someList 的元素 -->
<span class="sub-title">
<?+ $fn.encodeXssChar($item.subTitle) ?>
</span>
<? } ?>
</li>
<? endeach ?>
</ul>
特别注意:each和endeach只能放在独立的<? ?>标签内,不能跟其他语句同处一个标签内。除了下面这种情况。
在上面的模板中,如果不确定someList这个属性是否存在,可以像下面这样:
<? each $data.someList || [] ?>
TODO
<? endeach ?>
对输出内容进行编码,预防XSS攻击:
const render = compile('<?=: content ?>')
render({content: '<script>alert("1")</script>'})
// => <script>alert("1")</script>
// 即可在页面上正常显示:<script>alert("1")</script>
扩充默认的$encodeChars,扩充只影响当前模板:
const render = compile(`<? $encodeChars['b'] = 'B' ?><?=: content ?>`)
render({content: 'abc'})
// => aBc
手动调用$encode函数:
const render = compile(`<?+ $encode('Encode: ' + $data.content) ?>`)
render({content: '<b>abc</b>'})
// => Encode: <b>abc</b>
// 页面上正常显示:Encode: <b>abc</b>
compile('<p><?= hello ?>, <?= name ?>!</p>')
// 模板将被编译为如下函数
function anonymous($data, $fn) {
'use strict';
var $_get = function (data, key) {
return data[key] || (data[key] == null ? '' : data[key]);
};
var echo = '<p>'+ $_get($data, 'hello')+ ', '+ $_get($data, 'name')+ '!</p>';
return echo
}
compile(`
<h1><?= title ?></h1>
<ul>
<? each $data.someList ?>
<li>
<?= title ?>
</li>
<? endeach ?>
</ul>
`)
// 模板将被编译为如下函数
function anonymous($data, $fn) {
'use strict';
var $_get = function (data, key) {
return data[key] || (data[key] == null ? '' : data[key]);
};
var echo = '<h1>'+ $_get($data, 'title')+ '</h1><ul>';
~function () {
var $_list = $data.someList, $count = $_list.length, $i = 0, $item;
for (; $i < $count; $i++) {
$item = $_list[$i];
echo += '<li>'+ $_get($item, 'title')+ '</li>'
}
}();
echo += '</ul>';
return echo
}
compile('<p><?=: content ?></p>')
// 模板将被编译为如下函数
function anonymous($data, $fn) {
'use strict';
var $_get = function (data, key) {
return data[key] || (data[key] == null ? '' : data[key]);
};
var $encodeChars = {
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
var $encode = function (s) {
if (typeof s === 'string') {
var res = '', i = 0, l = s.length;
for (; i < l; i++) {
res += $encodeChars[s[i]] || s[i];
}
return res;
}
return s == null ? '' : s;
};
var echo = '<p>'+ $encode($_get($data, 'content'))+ '</p>';
return echo
}
FAQs
A small lightweight but powerful template engine.
We found that small-tpl demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.

Security News
TeamPCP is partnering with ransomware group Vect to turn open source supply chain attacks on tools like Trivy and LiteLLM into large-scale ransomware operations.