
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
yield-siftscience
Advanced tools
Promise-wrapped Sift Science lib for yielding. Also supports regular callback functions.
A promise-wrapped helper lib for yielding Sift Science API calls in nodejs.
Also supports regular callbacks.
$ npm install yield-siftscience
var siftscience = require('yield-siftscience')({
api_key: 'YOUR_SIFT_SCIENCE_REST_API_KEY'
});
['referral_code_redeemed', 'contacted_customer_support', ...])function(err, response) { ... } - can be used to override promise and make regular callback on all requests)[] - specify an array of sift science products. This parameter restricts the list of score or workflow decision retrieved to the specific products requested. more info. Possible values: Array with one or more of - ['payment_abuse','promo_abuse','content_abuse','account_abuse','legacy'])false - can be used to return score from sift science synchronously more info)false - can be used to return workflow status from sift science synchronously more info){} - see webhooks for usage)false - can be used to get extra params from sift science responses more info)Note: In v204 of the sift science API, return_action is deprecated in favor of the more granular combined use of abuse_types, return_score and return_workflow_status flags. more info
https://siftscience.com/developers/docs/curl/events-api
var result = yield siftscience.event.create_account({
'$session_id': session.id,
'$user_id': user.id,
'$user_email': user.email
});
var result = yield siftscience.event.login({
'$session_id': session.id,
'$user_id': user.id,
'$login_status': siftscience.CONSTANTS.STATUS.SUCCESS
});
var result = yield siftscience.event.custom_event('referral_code_redeemed', {
'$session_id': session.id,
'$user_id': user.id,
'code': 'abc123'
});
var result = yield siftscience.event.custom_event('contacted_customer_support', {
'$session_id': session.id,
'$user_id': user.id
});
Optionally, you can pass in an array of custom event names to add to the lib
var siftscience = require('yield-siftscience')({
api_key: 'YOUR_SIFT_SCIENCE_REST_API_KEY',
custom_events: ['referral_code_redeemed', 'contacted_customer_support', ...]
});
Then you could use
var result = yield siftscience.event.referral_code_redeemed({
'$session_id': session.id,
'$user_id': user.id,
'code': 'abc123'
});
var result = yield siftscience.event.contacted_customer_support({
'$session_id': session.id,
'$user_id': user.id,
});
https://siftscience.com/developers/docs/curl/labels-api
var result = yield siftscience.label(user.id, {
'$is_bad': true,
'$abuse_type': siftscience.CONSTANTS.ABUSE_TYPE.PAYMENT_ABUSE,
'$description': 'Because they are spamming and abusing our system',
'$source': 'manual review',
'$analyst': 'admin@example.com'
});
var result = yield siftscience.unlabel(user.id);
https://siftscience.com/developers/docs/curl/decisions-api
var result = yield siftscience.decision.status(siftscience.CONSTANTS.ENTITY_TYPE.USERS, entity.id)
var result = yield siftscience.decision.list(siftscience.CONSTANTS.ENTITY_TYPE.USER)
var result = yield siftscience.decision.apply(user.id, null, {
'decision_id': 'user_looks_ok_payment_abuse',
'source': siftscience.CONSTANTS.DECISION_SOURCE.MANUAL_REVIEW,
'analyst': 'analyst@email.com',
'description': 'applied via the high priority queue, queued user because their risk score exceeded 85'
})
var result = yield siftscience.decision.apply(user.id, order.id, {
'decision_id': 'user_looks_ok_payment_abuse',
'source': siftscience.CONSTANTS.DECISION_SOURCE.AUTOMATED_RULE,
'description': 'Auto block pending order as score exceeded risk threshold of 90'
})
https://siftscience.com/developers/docs/curl/workflows-api
var result = yield siftscience.workflow.status(workflow.id)
https://siftscience.com/developers/docs/curl/score-api
var result = yield siftscience.score(user.id);
https://siftscience.com/developers/docs/curl/device-fingerprinting-api
https://siftscience.com/developers/docs/javascript/javascript-api
Install the following JavaScript snippet on every public-facing page on your site. Do not include this snippet on internal tools or administration systems.
Replace 'UNIQUE_SESSION_ID', 'UNIQUE_USER_ID', and 'INSERT_JS_SNIPPET_KEY_HERE' with proper values
<script type="text/javascript">
var _user_id = 'UNIQUE_USER_ID';
var _session_id = 'UNIQUE_SESSION_ID';
var _sift = window._sift = window._sift || [];
_sift.push(['_setAccount', 'INSERT_JS_SNIPPET_KEY_HERE']);
_sift.push(['_setUserId', _user_id]);
_sift.push(['_setSessionId', _session_id]);
_sift.push(['_trackPageview']);
(function() {
function ls() {
var e = document.createElement('script');
e.src = 'https://cdn.siftscience.com/s.js';
document.body.appendChild(e);
}
if (window.attachEvent) {
window.attachEvent('onload', ls);
} else {
window.addEventListener('load', ls, false);
}
})();
</script>
An Account ID is required to use the fingerprint api. Get your Account ID
var siftscience = require('yield-siftscience')({
api_key: 'YOUR_SIFT_SCIENCE_REST_API_KEY',
account_id: 'YOUR_SIFT_SCIENCE_ACCOUNT_ID'
});
var result = yield siftscience.fingerprint.get_session(session.id);
var result = yield siftscience.fingerprint.get_device(device_fingerprint);
var result = yield siftscience.fingerprint.label_device(device_fingerprint, siftscience.CONSTANTS.DEVICE_LABEL.BAD);
var result = yield siftscience.fingerprint.get_devices(user.id);
https://siftscience.com/developers/docs/curl/partner-api
NOTE: I have not tested these as I do not have a partner account with sift science. Please report any bugs.
An Account & Partner ID are required to use the partner api. Get your Account & Partner ID
var siftscience = require('yield-siftscience')({
api_key: 'YOUR_SIFT_SCIENCE_REST_API_KEY',
account_id: 'YOUR_SIFT_SCIENCE_ACCOUNT_ID',
partner_id: 'YOUR_SIFT_SCIENCE_PARTNER_ID'
});
var result = yield siftscience.partner.create_account({
site_url: 'merchant123.com',
site_email: 'owner@merchant123.com',
analyst_email: 'john.doe@merchant123.com',
password: 's0mepA55word'
});
var result = yield siftscience.partner.list_accounts();
var result = yield siftscience.partner.configure_notifications({
email_notification_threshold: 0.5,
http_notification_threshold: 0.5,
http_notification_url: 'https://api.partner.com/notify?account=%s'
});
siftscience.score(user.id, function(_err, _response) {
if (_err) {
console.log(_err);
}
else {
var score = _response.body;
console.log(score);
}
});
var siftscience = require('yield-siftscience')({
api_key: 'YOUR_SIFT_SCIENCE_REST_API_KEY',
global_callback: function(_err, _response) {
if (_err) {
console.log(_err);
}
else {
var result = _response.body;
console.log(result);
}
}
});
siftscience.CONSTANTS = {
SHIPPING_METHOD: {
ELECTRONIC: '$electronic',
PHYSICAL: '$physical'
},
TRANSACTION_TYPE: {
SALE: '$sale',
AUTHORIZE: '$authorize',
CAPTURE: '$capture',
VOID: '$void',
REFUND: '$refund',
DEPOSIT: '$deposit',
WITHDRAWAL: '$withdrawal',
TRANSFER: '$transfer'
},
STATUS: {
SUCCESS: '$success',
FAILURE: '$failure',
PENDING: '$pending'
},
FAILURE_REASON: {
ALREADY_USED: '$already_used',
INVALID_CODE: '$invalid_code',
NOT_APPLICABLE: '$not_applicable',
EXPIRED: '$expired'
},
SOCIAL_SIGN_ON_TYPE: {
FACEBOOK: '$facebook',
GOOGLE: '$google',
YAHOO: '$yahoo',
TWITTER: '$twitter',
OTHER: '$other',
LINKEDIN: '$linkedin'
},
CONTENT_STATUS: {
DRAFT: '$draft',
PENDING: '$pending',
ACTIVE: '$active',
PAUSED: '$paused',
DELETED_BY_USER: '$deleted_by_user',
DELETED_BY_COMPANY: '$deleted_by_company'
},
CHARGEBACK_STATE: {
RECEIVED: '$received',
ACCEPTED: '$accepted',
DISPUTED: '$disputed',
WON: '$won',
LOST: '$lost'
},
CHARGEBACK_REASON: {
FRAUD: '$fraud',
DUPLICATE: '$duplicate',
PRODUCT_NOT_RECEIVED: '$product_not_received',
PRODUCT_UNACCEPTABLE: '$product_unacceptable',
OTHER: '$other'
},
ORDER_STATUS: {
APPROVED: '$approved',
CANCELED: '$canceled',
HELD: '$held',
FULFILLED: '$fulfilled',
RETURNED: '$returned'
},
ORDER_CANCEL_REASON: {
PAYMENT_RISK: '$payment_risk',
ABUSE: '$abuse',
POLICY: '$policy',
OTHER: '$other'
},
ORDER_STATUS_SOURCE: {
AUTOMATED: '$automated',
MANUAL_REVIEW: '$manual_review'
},
VERIFICATION_TYPE: {
SMS: '$sms',
PHONE_CALL: '$phone_call',
EMAIL: '$email',
APP_TFA: '$app_tfa',
CAPTCHA: '$captcha'
},
PAYMENT_TYPE: {
CASH: '$cash',
CHECK: '$check',
CREDIT_CARD: '$credit_card',
CRYPTO_CURRENCY: '$crypto_currency',
DIGITAL_WALLET: '$digital_wallet',
ELECTRONIC_FUND_TRANSFER: '$electronic_fund_transfer',
FINANCING: '$financing',
GIFT_CARD: '$gift_card',
INTERAC: '$interac', // Deprecated?
INVOICE: '$invoice',
MONEY_ORDER: '$money_order',
MASTERPASS: '$masterpass', // Deprecated?
POINTS: '$points',
STORE_CREDIT: '$store_credit',
THIRD_PARTY_PROCESSOR: '$third_party_processor',
VOUCHER: '$voucher'
},
RESPONSE_STATUS_MESSAGE: {
'-4': 'Service currently unavailable. Please try again later.',
'-3': 'Server-side timeout processing request. Please try again later.',
'-2': 'Unexpected server-side error',
'-1': 'Unexpected server-side error',
'0': 'Success',
'51': 'Invalid API key',
'52': 'Invalid characters in field name',
'53': 'Invalid characters in field value',
'54': 'Specified user_id has no scoreable events',
'55': 'Missing required field',
'56': 'Invalid JSON in request',
'57': 'Invalid HTTP body',
'60': 'Rate limited',
'104': 'Invalid API version',
'105': 'Not a valid reserved field',
'111': 'This feature is not enabled in your feature plan.'
},
REASON: {
CHARGEBACK: '$chargeback',
SPAM: '$spam',
FUNNELING: '$funneling',
FAKE: '$fake',
REFERRAL: '$referral',
DUPLICATE_ACCOUNT: '$duplicate_account'
},
DEVICE_LABEL: {
BAD: 'bad',
NOT_BAD: 'not_bad'
},
DEVICE_PERVASIVENESS: {
LOW: 'low',
MEDIUM: 'medium',
HIGH: 'high'
},
ABUSE_TYPE: {
PAYMENT_ABUSE: 'payment_abuse',
CONTENT_ABUSE: 'content_abuse',
PROMOTION_ABUSE: 'promotion_abuse',
PROMO_ABUSE: 'promo_abuse',
ACCOUNT_ABUSE: 'account_abuse',
LEGACY: 'legacy'
},
DECISION: {
PAYMENT_ABUSE: 'payment_abuse',
PROMOTION_ABUSE: 'promotion_abuse',
PROMO_ABUSE: 'promo_abuse',
CONTENT_ABUSE: 'content_abuse',
ACCOUNT_ABUSE: 'account_abuse',
LEGACY: 'legacy'
},
DECISION_CATEGORY: {
BLOCK: 'BLOCK',
WATCH: 'WATCH',
ACCEPT: 'ACCEPT'
},
DECISION_SOURCE: {
MANUAL_REVIEW: 'MANUAL_REVIEW',
AUTOMATED_RULE: 'AUTOMATED_RULE',
CHARGEBACK: 'CHARGEBACK'
},
STATE: {
RUNNING: 'running',
FINISHED: 'finished',
FAILED: 'failed'
},
ENTITY_TYPE: {
USERS: 'users',
ORDERS: 'orders',
USER: 'user',
ORDER: 'order'
},
APP: {
DECISION: 'decision',
REVIEW_QUEUE: 'review_queue',
USER_SCORER: 'user_scorer',
ORDER_SCORER: 'order_scorer',
EVENT_PROCESSOR: 'event_processor'
},
ACCOUNT_STATE: {
ACTIVE: 'ACTIVE',
DISABLED: 'DISABLED',
DELETED: 'DELETED'
}
};
NOTE: Currently only supports express/body-parser
$ npm install --save express
$ npm install --save body-parser
$ npm install --save yield-siftscience
Let's say you have created an action called "Test" with Action ID test
var express = require('express');
var bodyParser = require('body-parser');
// Require yield-siftscience with a webhooks mapping option
var siftscience = require('yield-siftscience')({
api_key: 'YOUR_SIFT_SCIENCE_REST_API_KEY',
webhooks: {
// This will receive all webhooks, regardless of Action ID
all: function(req, res, done) {
console.log('all: ', req.body);
done();
},
// This will receive webhooks with Action ID 'test'
test: function(req, res, done) {
console.log('test: ', req.body);
done();
}
}
});
// Set up the webhook listener
var app = express();
app.post('/siftscience', bodyParser.json(), siftscience.webhook.express());
app.listen(config.port);
https://siftscience.com/developers/docs/curl/apis-overview
$ cp test/config-example.js test/config.js
$ nano test/config.js
module.exports = {
api_key: 'xxxxxxxxxxxxxxxx',
js_key: 'xxxxxxxxxx',
account_id: 'xxxxxxxxxxxxxxxxxxxxxxxx',
workflow_run_id: 'xxxxxxxxxxxxx',
host: 'localhost',
port: 3000
};
$ npm install
$ npm test
Visiting the test web page will trigger a page view for user_id = '1' and session_id = '1'
http://localhost:3000
NOTE: You will have to run the test a second time if this is your first time visiting the test web page
CONSTANTS$verification eventsiftscience.unlabel() function signature has changed to support abuse typesiftscience.score() function signature has changed to support abuse typesreturn_action documentation - MORE INFOv203options arg - see USAGEreturn_action in init options - MORE INFOCONSTANTS object to siftscience object for things like $reasons and $shipping_method - see LABELS APIunlabel method to siftscience objectFAQs
Promise-wrapped Sift Science lib for yielding. Also supports regular callback functions.
We found that yield-siftscience 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.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.