axios 0.30.3 → 0.31.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -83,12 +83,6 @@ Using npm:
83
83
  $ npm install axios
84
84
  ```
85
85
 
86
- Using bower:
87
-
88
- ```bash
89
- $ bower install axios
90
- ```
91
-
92
86
  Using yarn:
93
87
 
94
88
  ```bash
@@ -336,13 +330,21 @@ These are the available config options for making requests. Only the `url` is re
336
330
 
337
331
  // `params` are the URL parameters to be sent with the request
338
332
  // Must be a plain object or a URLSearchParams object
333
+ // Null bytes in param values stay percent-encoded as `%00` in the resulting query string
334
+ // (GHSA-xhjh-pmcv-23jw) — Axios does not reverse `encodeURIComponent` output for `%00`,
335
+ // so null-byte injection cannot be smuggled through the serializer.
339
336
  params: {
340
337
  ID: 12345
341
338
  },
342
339
 
343
340
  // `paramsSerializer` is an optional config in charge of serializing `params`
341
+ // Nested objects are walked with a bounded recursion depth (GHSA-62hf-57xw-28j9):
342
+ // once `maxDepth` is exceeded the serializer throws `ERR_FORM_DATA_DEPTH_EXCEEDED`
343
+ // instead of overflowing the call stack. The same cap applies to `toFormData` when
344
+ // `Content-Type: multipart/form-data` triggers automatic FormData serialization.
344
345
  paramsSerializer: {
345
- indexes: null // array indexes format (null - no brackets, false - empty brackets, true - brackets with indexes)
346
+ indexes: null, // array indexes format (null - no brackets, false - empty brackets, true - brackets with indexes)
347
+ maxDepth: 100 // maximum recursion depth for nested params (default: 100, Infinity disables the limit)
346
348
  },
347
349
 
348
350
  // `data` is the data to be sent as the request body
@@ -400,6 +402,9 @@ These are the available config options for making requests. Only the `url` is re
400
402
  xsrfHeaderName: 'X-XSRF-TOKEN', // default
401
403
 
402
404
  // `undefined` (default) - set XSRF header only for the same origin requests
405
+ // Only an explicit `true` (own property on the config) will add the XSRF header for
406
+ // cross-origin requests. Values inherited from `Object.prototype` are ignored
407
+ // (GHSA-xx6v-rp6x-q39c), so a polluted prototype cannot silently enable the token.
403
408
  withXSRFToken: boolean | undefined | ((config: AxiosRequestConfig) => boolean | undefined),
404
409
 
405
410
  // `onUploadProgress` allows handling of progress events for uploads
@@ -415,9 +420,13 @@ These are the available config options for making requests. Only the `url` is re
415
420
  },
416
421
 
417
422
  // `maxContentLength` defines the max size of the http response content in bytes allowed in node.js
423
+ // Also enforced on streamed responses (`responseType: 'stream'`): bytes are counted as they
424
+ // arrive and the stream is aborted with an error once the cap is exceeded (GHSA-vf2m-468p-8v99).
418
425
  maxContentLength: 2000,
419
426
 
420
427
  // `maxBodyLength` (Node only option) defines the max size of the http request content in bytes allowed
428
+ // Also enforced on stream uploads: uploaded bytes are tracked and the request is aborted
429
+ // once the cap is exceeded, even when the native http transport is used directly.
421
430
  maxBodyLength: 2000,
422
431
 
423
432
  // `validateStatus` defines whether to resolve or reject the promise for a given
@@ -522,6 +531,7 @@ These are the available config options for making requests. Only the `url` is re
522
531
  dots: boolean; // use dots instead of brackets format
523
532
  metaTokens: boolean; // keep special endings like {} in parameter key
524
533
  indexes: boolean; // array indexes format null - no brackets, false - empty brackets, true - brackets with indexes
534
+ maxDepth: number; // maximum recursion depth for nested objects (default: 100, Infinity disables the limit)
525
535
  }
526
536
  }
527
537
  ```
@@ -603,6 +613,8 @@ instance.defaults.headers.common['Authorization'] = AUTH_TOKEN;
603
613
 
604
614
  Config will be merged with an order of precedence. The order is library defaults found in [lib/defaults.js](https://github.com/axios/axios/blob/master/lib/defaults/index.js#L28), then `defaults` property of the instance, and finally `config` argument for the request. The latter will take precedence over the former. Here's an example.
605
615
 
616
+ > Note: the merged config object is created with a null prototype (`Object.create(null)`) and only own properties of the inputs are copied across. A polluted `Object.prototype` cannot leak values (for example `transport`, `adapter`, or `transformRequest`) into the outgoing config through inheritance, and keys such as `__proto__`, `constructor`, and `prototype` are dropped during the merge.
617
+
606
618
  ```js
607
619
  // Create an instance using the config defaults provided by the library
608
620
  // At this point the timeout config value is `0` as is the default for the library
@@ -1011,6 +1023,13 @@ The back-end body-parser could potentially use this meta-information to automati
1011
1023
  - `false`(default) - add empty brackets (`arr[]: 1`, `arr[]: 2`, `arr[]: 3`)
1012
1024
  - `true` - add brackets with indexes (`arr[0]: 1`, `arr[1]: 2`, `arr[2]: 3`)
1013
1025
 
1026
+ - `maxDepth: number = 100` - maximum recursion depth when serializing nested objects. Throws an `AxiosError` with
1027
+ code `ERR_FORM_DATA_DEPTH_EXCEEDED` if the limit is exceeded. Set to `Infinity` to disable the limit.
1028
+
1029
+ > **Security note:** If your server-side code forwards client-supplied objects to axios as request `data` or `params`,
1030
+ > keep `maxDepth` at a reasonable value (the default of 100 is sufficient for most use cases) to prevent
1031
+ > denial-of-service via deeply nested payloads.
1032
+
1014
1033
  Let's say we have an object like this one:
1015
1034
 
1016
1035
  ```js
package/UPGRADE_GUIDE.md CHANGED
@@ -159,8 +159,8 @@ axios.get('some/url')
159
159
  Previous versions of axios shipped with an AMD, CommonJS, and Global build. This has all been rolled into a single UMD build.
160
160
 
161
161
  ```js
162
- // AMD
163
- require(['bower_components/axios/dist/axios'], function (axios) {
162
+ // AMD (for example with a RequireJS path mapped to `axios/dist/axios`)
163
+ require(['axios/dist/axios'], function (axios) {
164
164
  /* ... */
165
165
  });
166
166
 
package/dist/axios.js CHANGED
@@ -1,4 +1,4 @@
1
- // axios v0.30.3 Copyright (c) 2026 Matt Zabriskie
1
+ // axios v0.31.1 Copyright (c) 2026 Matt Zabriskie
2
2
  (function (global, factory) {
3
3
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
4
4
  typeof define === 'function' && define.amd ? define(factory) :
@@ -140,7 +140,15 @@
140
140
  * @return {boolean} True if value is a empty Object, otherwise false
141
141
  */
142
142
  function isEmptyObject(val) {
143
- return val && Object.keys(val).length === 0 && Object.getPrototypeOf(val) === Object.prototype;
143
+ if (!isPlainObject(val)) {
144
+ return false;
145
+ }
146
+ for (var key in val) {
147
+ if (Object.prototype.hasOwnProperty.call(val, key)) {
148
+ return false;
149
+ }
150
+ }
151
+ return true;
144
152
  }
145
153
 
146
154
  /**
@@ -207,11 +215,17 @@
207
215
  */
208
216
  function isFormData(thing) {
209
217
  var pattern = '[object FormData]';
210
- return thing && (
211
- (typeof FormData === 'function' && thing instanceof FormData) ||
212
- toString.call(thing) === pattern ||
213
- (isFunction(thing.toString) && thing.toString() === pattern)
214
- );
218
+ if (!thing) return false;
219
+ if (typeof FormData === 'function' && thing instanceof FormData) return true;
220
+ // Reject non-objects (strings, numbers, booleans) up front — Object.getPrototypeOf
221
+ // throws a TypeError on primitives in ES5 environments.
222
+ if (!isObject(thing)) return false;
223
+ // Reject plain objects inheriting directly from Object.prototype so prototype-pollution gadgets can't spoof FormData (GHSA-6chq-wfr3-2hj9).
224
+ var proto = Object.getPrototypeOf(thing);
225
+ if (!proto || proto === Object.prototype) return false;
226
+ if (!isFunction(thing.append)) return false;
227
+ return toString.call(thing) === pattern ||
228
+ (isFunction(thing.toString) && thing.toString() === pattern);
215
229
  }
216
230
 
217
231
  /**
@@ -598,7 +612,8 @@
598
612
  'ERR_BAD_REQUEST',
599
613
  'ERR_CANCELED',
600
614
  'ERR_NOT_SUPPORT',
601
- 'ERR_INVALID_URL'
615
+ 'ERR_INVALID_URL',
616
+ 'ERR_FORM_DATA_DEPTH_EXCEEDED'
602
617
  // eslint-disable-next-line func-names
603
618
  ].forEach(function(code) {
604
619
  descriptors[code] = {value: code};
@@ -699,6 +714,7 @@
699
714
  var dots = options.dots;
700
715
  var indexes = options.indexes;
701
716
  var _Blob = options.Blob || typeof Blob !== 'undefined' && Blob;
717
+ var maxDepth = options.maxDepth === undefined ? 100 : options.maxDepth;
702
718
  var useBlob = _Blob && isSpecCompliant(formData);
703
719
 
704
720
  if (!utils.isFunction(visitor)) {
@@ -775,9 +791,19 @@
775
791
  isVisitable: isVisitable
776
792
  });
777
793
 
778
- function build(value, path) {
794
+ function build(value, path, depth) {
779
795
  if (utils.isUndefined(value)) return;
780
796
 
797
+ // eslint-disable-next-line no-param-reassign
798
+ depth = depth || 0;
799
+
800
+ if (depth > maxDepth) {
801
+ throw new AxiosError_1(
802
+ 'Maximum object depth of ' + maxDepth + ' exceeded (got ' + depth + ' levels)',
803
+ AxiosError_1.ERR_FORM_DATA_DEPTH_EXCEEDED
804
+ );
805
+ }
806
+
781
807
  if (stack.indexOf(value) !== -1) {
782
808
  throw Error('Circular reference detected in ' + path.join('.'));
783
809
  }
@@ -790,7 +816,7 @@
790
816
  );
791
817
 
792
818
  if (result === true) {
793
- build(el, path ? path.concat(key) : [key]);
819
+ build(el, path ? path.concat(key) : [key], depth + 1);
794
820
  }
795
821
  });
796
822
 
@@ -801,7 +827,7 @@
801
827
  throw new TypeError('data must be an object');
802
828
  }
803
829
 
804
- build(obj);
830
+ build(obj, null, 0);
805
831
 
806
832
  return formData;
807
833
  }
@@ -809,16 +835,17 @@
809
835
  var toFormData_1 = toFormData;
810
836
 
811
837
  function encode$1(str) {
838
+ // Do not map `%00` back to a raw null byte (GHSA-xhjh-pmcv-23jw): that reversed
839
+ // the safe percent-encoding from encodeURIComponent and enabled null byte injection.
812
840
  var charMap = {
813
841
  '!': '%21',
814
842
  "'": '%27',
815
843
  '(': '%28',
816
844
  ')': '%29',
817
845
  '~': '%7E',
818
- '%20': '+',
819
- '%00': '\x00'
846
+ '%20': '+'
820
847
  };
821
- return encodeURIComponent(str).replace(/[!'\(\)~]|%20|%00/g, function replacer(match) {
848
+ return encodeURIComponent(str).replace(/[!'\(\)~]|%20/g, function replacer(match) {
822
849
  return charMap[match];
823
850
  });
824
851
  }
@@ -1335,7 +1362,8 @@
1335
1362
  var requestData = config.data;
1336
1363
  var requestHeaders = config.headers;
1337
1364
  var responseType = config.responseType;
1338
- var withXSRFToken = config.withXSRFToken;
1365
+ // Guard against prototype pollution (GHSA-xx6v-rp6x-q39c): only honor own properties.
1366
+ var withXSRFToken = utils.hasOwnProperty(config, 'withXSRFToken') ? config.withXSRFToken : undefined;
1339
1367
  var onCanceled;
1340
1368
  function done() {
1341
1369
  if (config.cancelToken) {
@@ -1463,8 +1491,11 @@
1463
1491
  // Specifically not if we're in a web worker, or react-native.
1464
1492
  if (utils.isStandardBrowserEnv()) {
1465
1493
  // Add xsrf header
1466
- withXSRFToken && utils.isFunction(withXSRFToken) && (withXSRFToken = withXSRFToken(config));
1467
- if (withXSRFToken || (withXSRFToken !== false && isURLSameOrigin(fullPath))) {
1494
+ if (utils.isFunction(withXSRFToken)) {
1495
+ withXSRFToken = withXSRFToken(config);
1496
+ }
1497
+ // Strict boolean check (GHSA-xx6v-rp6x-q39c): only `true` short-circuits the same-origin guard.
1498
+ if (withXSRFToken === true || (withXSRFToken !== false && isURLSameOrigin(fullPath))) {
1468
1499
  // Add xsrf header
1469
1500
  var xsrfValue = config.xsrfHeaderName && config.xsrfCookieName && cookies.read(config.xsrfCookieName);
1470
1501
  if (xsrfValue) {
@@ -1622,17 +1653,20 @@
1622
1653
  var isFileList;
1623
1654
 
1624
1655
  if (isObjectPayload) {
1656
+ var formSerializer = utils.hasOwnProperty(this, 'formSerializer') ? this.formSerializer : undefined;
1657
+ var envOption = utils.hasOwnProperty(this, 'env') ? this.env : undefined;
1658
+
1625
1659
  if (contentType.indexOf('application/x-www-form-urlencoded') !== -1) {
1626
- return toURLEncodedForm(data, this.formSerializer).toString();
1660
+ return toURLEncodedForm(data, formSerializer).toString();
1627
1661
  }
1628
1662
 
1629
1663
  if ((isFileList = utils.isFileList(data)) || contentType.indexOf('multipart/form-data') > -1) {
1630
- var _FormData = this.env && this.env.FormData;
1664
+ var _FormData = envOption && envOption.FormData;
1631
1665
 
1632
1666
  return toFormData_1(
1633
1667
  isFileList ? {'files[]': data} : data,
1634
1668
  _FormData && new _FormData(),
1635
- this.formSerializer
1669
+ formSerializer
1636
1670
  );
1637
1671
  }
1638
1672
  }
@@ -1730,6 +1764,25 @@
1730
1764
  return !!(value && value.__CANCEL__);
1731
1765
  };
1732
1766
 
1767
+ var INVALID_HEADER_VALUE_RE = /[^\x09\x20-\x7E\x80-\xFF]/g;
1768
+ var BOUNDARY_WHITESPACE_RE = /^[\x09\x20]+|[\x09\x20]+$/g;
1769
+
1770
+ function sanitizeHeaderValue(value) {
1771
+ if (value === false || value == null) {
1772
+ return value;
1773
+ }
1774
+
1775
+ if (utils.isArray(value)) {
1776
+ return value.map(sanitizeHeaderValue);
1777
+ }
1778
+
1779
+ return String(value)
1780
+ .replace(INVALID_HEADER_VALUE_RE, '')
1781
+ .replace(BOUNDARY_WHITESPACE_RE, '');
1782
+ }
1783
+
1784
+ var sanitizeHeaderValue_1 = sanitizeHeaderValue;
1785
+
1733
1786
  /**
1734
1787
  * Throws a `CanceledError` if cancellation has been requested.
1735
1788
  */
@@ -1781,6 +1834,10 @@
1781
1834
  }
1782
1835
  );
1783
1836
 
1837
+ utils.forEach(config.headers, function sanitizeHeaderConfigValue(value, header) {
1838
+ config.headers[header] = sanitizeHeaderValue_1(value);
1839
+ });
1840
+
1784
1841
  var adapter = config.adapter || defaults_1.adapter;
1785
1842
 
1786
1843
  return adapter(config).then(function onAdapterResolution(response) {
@@ -1827,7 +1884,17 @@
1827
1884
  var mergeConfig = function mergeConfig(config1, config2) {
1828
1885
  // eslint-disable-next-line no-param-reassign
1829
1886
  config2 = config2 || {};
1830
- var config = {};
1887
+ // Use a null-prototype object so a polluted Object.prototype cannot leak
1888
+ // values (e.g. transport, adapter) into the returned config via inheritance.
1889
+ var config = Object.create(null);
1890
+
1891
+ function getOwn(source, prop) {
1892
+ return utils.hasOwnProperty(source, prop) ? source[prop] : undefined;
1893
+ }
1894
+
1895
+ function hasOwn(source, prop) {
1896
+ return utils.hasOwnProperty(source, prop);
1897
+ }
1831
1898
 
1832
1899
  function getMergedValue(target, source) {
1833
1900
  if (utils.isPlainObject(target) && utils.isPlainObject(source)) {
@@ -1844,34 +1911,34 @@
1844
1911
 
1845
1912
  // eslint-disable-next-line consistent-return
1846
1913
  function mergeDeepProperties(prop) {
1847
- if (!utils.isUndefined(config2[prop])) {
1848
- return getMergedValue(config1[prop], config2[prop]);
1849
- } else if (!utils.isUndefined(config1[prop])) {
1914
+ if (hasOwn(config2, prop) && !utils.isUndefined(config2[prop])) {
1915
+ return getMergedValue(getOwn(config1, prop), config2[prop]);
1916
+ } else if (hasOwn(config1, prop) && !utils.isUndefined(config1[prop])) {
1850
1917
  return getMergedValue(undefined, config1[prop]);
1851
1918
  }
1852
1919
  }
1853
1920
 
1854
1921
  // eslint-disable-next-line consistent-return
1855
1922
  function valueFromConfig2(prop) {
1856
- if (!utils.isUndefined(config2[prop])) {
1923
+ if (hasOwn(config2, prop) && !utils.isUndefined(config2[prop])) {
1857
1924
  return getMergedValue(undefined, config2[prop]);
1858
1925
  }
1859
1926
  }
1860
1927
 
1861
1928
  // eslint-disable-next-line consistent-return
1862
1929
  function defaultToConfig2(prop) {
1863
- if (!utils.isUndefined(config2[prop])) {
1930
+ if (hasOwn(config2, prop) && !utils.isUndefined(config2[prop])) {
1864
1931
  return getMergedValue(undefined, config2[prop]);
1865
- } else if (!utils.isUndefined(config1[prop])) {
1932
+ } else if (hasOwn(config1, prop) && !utils.isUndefined(config1[prop])) {
1866
1933
  return getMergedValue(undefined, config1[prop]);
1867
1934
  }
1868
1935
  }
1869
1936
 
1870
1937
  // eslint-disable-next-line consistent-return
1871
1938
  function mergeDirectKeys(prop) {
1872
- if (prop in config2) {
1873
- return getMergedValue(config1[prop], config2[prop]);
1874
- } else if (prop in config1) {
1939
+ if (hasOwn(config2, prop)) {
1940
+ return getMergedValue(getOwn(config1, prop), config2[prop]);
1941
+ } else if (hasOwn(config1, prop)) {
1875
1942
  return getMergedValue(undefined, config1[prop]);
1876
1943
  }
1877
1944
  }
@@ -1920,7 +1987,7 @@
1920
1987
  };
1921
1988
 
1922
1989
  var data = {
1923
- version: "0.30.3",
1990
+ "version": "0.31.1"
1924
1991
  };
1925
1992
 
1926
1993
  var VERSION = data.version;