Uh oh!
There was an error while loading. Please reload this page.
Use HTTPS for Wikimedia query-help links - #22410
Conversation
geoffw0
left a comment
There was a problem hiding this comment.
LGTM.
(I checked a handful of the new URLs manually, and had Copilot look for unusual cases)
| <!-- | ||
| <p>Wikipedia article on the <a href="http://en.wikipedia.org/wiki/Double-checked_locking">Double-Checked Locking Pattern</a></p> | ||
| <p>Wikipedia article on the <a href="https://en.wikipedia.org/wiki/Double-checked_locking">Double-Checked Locking Pattern</a></p> |
There was a problem hiding this comment.
This change is in a comment, but it's not doing any harm to update it along with the others.
QHelp previews: cpp/ql/src/Best Practices/Exceptions/CatchingByValue.qhelpCatching by valueCatching an exception by value will create a new local variable which is a copy of the originally thrown object. Creating the copy is slightly wasteful, but not catastrophic. More worrisome is the fact that if the type being caught is a strict supertype of the originally thrown type, then the copy might not contain as much information as the original exception. RecommendationThe parameter to the Examplevoidbad() {
try {
/* ... */
}
catch(std::exception a_copy_of_the_thrown_exception) {
// Do something with a_copy_of_the_thrown_exception
}
}
voidgood() {
try {
/* ... */
}
catch(const std::exception& the_thrown_exception) {
// Do something with the_thrown_exception
}
}
References
cpp/ql/src/Best Practices/Exceptions/ThrowingPointers.qhelpThrowing pointersAs C++ is not a garbage collected language, exceptions should not be dynamically allocated. Dynamically allocating an exception puts an onus on every As a special case, it is permissible to throw anything derived from Microsoft MFC's RecommendationThe Examplevoidbad() {
thrownewstd::exception("This is how not to throw an exception");
}
voidgood() {
throwstd::exception("This is how to throw an exception");
}
References
cpp/ql/src/Best Practices/Likely Errors/OffsetUseBeforeRangeCheck.qhelpArray offset used before range checkThe program contains an and-expression where the array access is defined before the range check. Consequently the array is accessed without any bounds checking. The range check does not protect the program from segmentation faults caused by attempts to read beyond the end of a buffer. RecommendationUpdate the and-expression so that the range check precedes the array offset. This will ensure that the bounds are checked before the array is accessed. ExampleThe intfind(intstart, char*str, chargoal)
{
intlen=strlen(str);
//Potential buffer overflowfor (inti=start; str[i] !=0&&i<len; i++) { if (str[i] ==goal)
returni; }
return-1;
}
intfindRangeCheck(intstart, char*str, chargoal)
{
intlen=strlen(str);
//Range check protects against buffer overflowfor (inti=start; i<len&&str[i] !=0 ; i++) {
if (str[i] ==goal)
returni; }
return-1;
}
Update the and-expression so that the range check precedes the array offset (for example, the References
cpp/ql/src/Best Practices/Likely Errors/Slicing.qhelpSlicingThis query finds assignments of a non-reference instance of a derived type to a variable of the base type where the derived type has more fields than the base. These assignments slice off all the fields added by the derived type, and can cause unexpected state when accessed as the derived type. RecommendationChange the type of the variable at the left-hand side of the assignment to the subclass. Examplestaticint idctr = 0;
//Basic connection with idclassConnection {
public:int connId;
virtualvoidprint_info() {
cout << "id: " << connId << "\n";
}
Connection() {
connId = idctr++;
}
};
//Adds counters, and an overriding print_infoclassMeteredConnection : publicConnection {
public:int txCtr;
int rxCtr;
MeteredConnection() {
txCtr = 0;
rxCtr = 0;
}
virtualvoidprint_info() {
cout << "id: " << connId << "\n" << "tx/rx: " << txCtr << "/" << rxCtr << "\n";
}
};
intmain(int argc, char* argv[]) {
Connection conn;
MeteredConnection m_conn;
Connection curr_conn = conn;
curr_conn.print_info();
curr_conn = m_conn; //Wrong: Derived MetricConnection assigned to Connection //variable, will slice off the counters and the overriding print_info
curr_conn.print_info(); //Will not print the counters.
Connection* curr_pconn = &conn;
curr_pconn->print_info();
curr_pconn = &m_conn; //Correct: Pointer assigned to address of the MetricConnection. //Counters and virtual functions remain intact.
curr_pconn->print_info(); //Will call the correct method MeteredConnection::print_info
}
References
cpp/ql/src/Best Practices/Magic Constants/MagicConstantsNumbers.qhelpMagic numbersA magic number is a numeric literal (for example,
RecommendationConsider creating a Examplevoidsanitize(Fields[] record) {
//The number of fields here can be put in a constfor (fieldCtr = 0; field < 7; field++) {
sanitize(fields[fieldCtr]);
}
}
#defineNUM_FIELDS7voidprocess(Fields[] record) {
//This avoids using a magic constant by using the macro insteadfor (fieldCtr = 0; field < NUM_FIELDS; field++) {
process(fields[fieldCtr]);
}
}
References
cpp/ql/src/Best Practices/Magic Constants/MagicConstantsString.qhelpMagic stringsA magic string is a string literal (for example,
RecommendationConsider replacing the magic string with a new named constant. References
cpp/ql/src/Best Practices/RuleOfThree.qhelpRule of threeThis query finds classes that define a destructor, a copy constructor, or a copy assignment operator, but not all three of them. The compiler generates default implementations for these functions, and since they deal with similar concerns it is likely that if the default implementation of one of them is not satisfactory, then neither are those of the others. The query flags any such class with a warning, and also display the list of generated warnings in the result view. RecommendationExplicitly define the missing functions. References
cpp/ql/src/Best Practices/RuleOfTwo.qhelpInconsistent definition of copy constructor and assignment ('Rule of Two')This rule finds classes that define a copy constructor or a copy assignment operator, but not both of them. The compiler generates default implementations for these functions, and since they deal with similar concerns it is likely that if the default implementation of one of them is not satisfactory, then neither is that of the other. When a class defines a copy constructor or a copy assignment operator, but not both, this can cause unexpected behavior. The object initialization (that is, RecommendationFirst, consider whether the user-defined member needs to be explicitly defined at all. If no user-defined copy constructor is provided for a class, the compiler will always attempt to generate a public copy constructor that recursively invokes the copy constructor of each field. If the existing user-defined copy constructor does exactly the same, it is most likely beneficial to delete it. The compiler-generated version may be more efficient, and it does not need to be manually maintained as fields are added and deleted. If the user-defined member does need to exist, the other corresponding member should be defined too. It can be defined as defaulted (using ExampleclassC {
private:
Other* other = NULL;
public:C(const C& copyFrom) {
Other* newOther = newOther();
*newOther = copyFrom.other;
this->other = newOther;
}
//No operator=, by default will just copy the pointer other, will not create a new object
};
classD {
Other* other = NULL;
public:
D& operator=(D& rhs) {
Other* newOther = newOther();
*newOther = rhs.other;
this->other = newOther;
return *this;
}
//No copy constructor, will just copy the pointer other and not create a new object
};
References
cpp/ql/src/Documentation/DocumentApi.qhelpUndocumented API functionFunctions that are called from lots of different places are usually important, and justify having documentation written for them. In particular, if a function is defined in a file, and is called from at least two other files, then the function should probably be documented. As an exception, because their purpose is usually obvious, it is not necessary to document constructors, destructors, implementations of RecommendationAdd comments to document the purpose of the function. In particular, ensure that the public API of the function is carefully documented. This reduces the chance that a future change to the function will introduce a defect by changing the API and breaking the expectations of the calling functions. References
cpp/ql/src/Documentation/FixmeComments.qhelpFIXME commentThe indicated comment is a FIXME comment. FIXME comments are often used to indicate code that does not work correctly or that may not work in all supported environments. This may be necessary during the implementation of new functionality but FIXME comments should not be present in stable code. Any FIXME comments should be reviewed and the code improved as soon as possible to avoid the accumulation of partially implemented features. RecommendationFix the functionality indicated by the comment. If the comment no longer applies, delete it to avoid confusion. ExampleintisEven(int n) {
//FIXME: Is only correct for small values of nreturn n == 0 || n == 2;
}References
cpp/ql/src/Documentation/TodoComments.qhelpTODO commentThe indicated comment is a TODO comment. TODO comments are often used to indicate code that is incomplete. This may be necessary during the implementation of new functionality but TODO comments should not be present in stable code. Any TODO comments should be reviewed and the code completed as soon as possible to avoid the accumulation of partially implemented features. RecommendationImplement the functionality indicated by the comment. If the comment no longer applies, delete it to avoid confusion. ExampleintisOdd(int n) {
//TODO: Works only for positive n. Need to check if negative n is valid inputreturn (n % 2) == 1;
}References
cpp/ql/src/Documentation/UncommentedFunction.qhelpPoorly documented large functionThis rule finds large functions that have too few comment lines. Documentation becomes more important as a function becomes more complex, and a lack of documentation makes it harder to maintain. RecommendationAdd comments to document the purpose of the function. Large, complex functions in particular require detailed documentation, not only because they are harder to understand, but the process of documentation may reveal that the function could be split into smaller, more cohesive functions. Referencescpp/ql/src/Header Cleanup/Cleanup-DuplicateIncludeGuard.qhelpDuplicate include guardA common pattern in header files is to use pre-processor directives to guard a header file against being processed more than once per translation unit. This practice is intended to prevent compilation errors. However, pre-processor include guards are prone to human error themselves because each include guard must be assigned a unique macro name to function correctly. If two header files share the same guard macro, the compiler may unexpectedly skip the second file it encounters, leading to compilation errors or configuration bugs. The query will flag the pre-processor RecommendationFirst decide whether the duplicate include guard is dangerous. A duplicate include guard may cause the header file to be skipped over when it shouldn't be, but occasionally this design is used on purpose to 'override' an existing header file. To address the issue, rename the macros used by all but one instance of the duplicate include guard. Remember to change both the ExampleHere's an example of two header files that have accidentally been given the same include guard macro. To fix the issue, rename both occurrences of the macro in the second file, for example to ANOTHER_HEADER_FILE_H. // header_file.h
#ifndef HEADER_FILE_H
#defineHEADER_FILE_H// ...
#endif// HEADER_FILE_H// another_header_file.h
#ifndef HEADER_FILE_H // should be ANOTHER_HEADER_FILE_H
#defineHEADER_FILE_H// should be ANOTHER_HEADER_FILE_H// ...
#endif// HEADER_FILE_HReferences
cpp/ql/src/Likely Bugs/Arithmetic/BadCheckOdd.qhelpBad check for oddnessThis rule finds code that uses RecommendationConsider using References
cpp/ql/src/Likely Bugs/Likely Typos/AssignWhereCompareMeant.qhelpAssignment where comparison was intendedThis rule finds uses of the assignment operator The rule flags every occurrence of an assignment in a position where its result is interpreted as a truth value. An assignment is only flagged if its right hand side is a compile-time constant. RecommendationCheck to ensure that the flagged expressions are not typos. If an assignment is really intended to be treated as a truth value, it may be better to surround it with parentheses. Exampleif(p = NULL) { //most likely == was intended. Otherwise it evaluates to the value//of the rhs of the assignment (which is NULL)
...
}
References
cpp/ql/src/Likely Bugs/Likely Typos/CompareWhereAssignMeant.qhelpComparison where assignment was intendedThis rule finds uses of the equality operator The rule flags every occurrence of an equality operator in a position where its result is discarded. RecommendationCheck to ensure that the flagged expressions are not typos. If the result of an equality test is really intended to be discarded, it should be explicitly cast to Exampleint x;
x == 4; // most likely = was intended. Otherwise this statement has no effect.
...
References
cpp/ql/src/Likely Bugs/OO/IncorrectConstructorDelegation.qhelpIncorrect constructor delegationPrior to C++11, there is no mechanism for a constructor to delegate part of the object initialization to another, although other languages provide this feature. Consequently, any instance where a constructor call appears in the body of a constructor without being used is suspect. RecommendationThe rule flags constructor calls in constructors which are not used in some way. This is usually a misguided attempt to share some initialization code between multiple constructors, or to provide sensible defaults for some constructor parameters. The effect of a flagged expression would be to initialize an instance of the current class on the stack, and then let it go out of scope at the end of the constructor call. There are several ways to address the underlying issue of sharing initialization code, and the most appropriate needs to picked in each case. Roughly speaking, the options are:
ExampleclassCircle {
private:double m_x;
double m_y;
double m_radius;
double m_area;
public:// Real constructor:Circle(double x, double y, double radius) :
m_x(x), m_y(y), m_radius(radius)
{
m_area = 3.14159 * m_radius * m_radius;
}
Circle() {
// WRONG: Attempt to define the unit circle by default fails.Circle(0, 0, 1);
}
};
References
cpp/ql/src/Metrics/Files/FCommentRatio.qhelpPercentage of commentsThis metric measures the percentage of lines in a file that contain a comment or are part of a multi-line comment. Having a low percentage of comments is an indication that a file does not have sufficient documentation. Undocumented code is hard to understand, modify, and reuse. RecommendationAdd documentation to files with a low percentage of comments. It is most useful to start documenting the public functions first. Referencescpp/ql/src/Metrics/Files/FCyclomaticComplexity.qhelpAverage cyclomatic complexity of filesThis metric measures the average cyclomatic complexity of the functions in a file. The cyclomatic complexity of a function is the number of linearly independent execution paths through that function. A path is linearly independent path if it differs from all other paths by at least one node. Straight-line code therefore has a cyclomatic complexity of one, while branches, switches and loops increase cyclomatic complexity. Functions with a high cyclomatic complexity are typically hard to understand and test. By extension, files whose functions have a high average cyclomatic complexity are problematic, and usually would benefit from refactoring. As a concrete example, consider the following function: intf(int i, int j) {
// startint result;
if(i % 2 == 0) {
// iEven
result = i + j;
}
else {
// iOddif(j % 2 == 0) {
// jEven
result = i * j;
}
else {
// jOdd
result = i - j;
}
}
return result;
// end
}The control flow graph for this function is as follows:
RecommendationFunctions with a high cyclomatic complexity should be simplified, for instance by tidying up any complex logic within them or by splitting them into multiple methods using the Extract Method refactoring. References
cpp/ql/src/Metrics/Files/FLinesOfCode.qhelpLines of code in filesThis metric measures the number of lines of code in a file. This excludes comments and blank lines. Having too many lines of code in a file is an indication that it can be split into several files of more manageable size. Generated code is a notable exception to this. RecommendationLong files should be examined to see if they can be split into smaller, more cohesive files. References
cpp/ql/src/Metrics/Files/FLinesOfComments.qhelpLines of comments in filesThis metric measures the number of lines of comments in a file. Files that have too few comments are more likely to be insufficiently documented. Long files that have no comments at all require particular scrutiny, as these are more likely to need explicit documentation in comments. RecommendationFiles with few to no comments should be examined to see if they require documentation. Particular attention should be given to long files. Referencescpp/ql/src/Metrics/Files/FTodoComments.qhelpNumber of todo/fixme comments per fileThis metric measures the number of TODO or FIXME comments in the code. These comments tend to document points of ambiguity in the software's requirements. Often they refer to corner-cases that are not handled or potential defects. It is therefore very important to monitor such comments and, where appropriate, escalate comments to an defect-tracking system or other means of ensuring that action is taken. RecommendationRemove unnecessary TODO/FIXME comments, and those that are no longer relevant. File tickets for the remaining comments in a defect-tracker, or otherwise ensure that someone is responsible for fixing them. Referencescpp/ql/src/Metrics/Functions/FunLinesOfComments.qhelpLines of comments per functionThis metric measures the number of lines of comments in a function. Functions that have too few comments are more likely to be insufficiently documented. Long, complex functions that have no comments at all require particular scrutiny, as these are more likely to need explicit documentation in comments. RecommendationFunctions with few to no comments should be examined to see if they require documentation. Particular attention should be given to long, complex functions. Referencescpp/ql/src/Metrics/Functions/FunPercentageOfComments.qhelpComment ratio per functionThis metric measures the percentage of lines in an function that contain a comment or are part of a multi-line comment. Having a low comment ratio is an indication that a function does not have sufficient documentation. RecommendationStart by adding documentation to functions that are used from other parts of the code. Then document large complex functions, as they benefit most from documentation. Referencescpp/ql/src/Security/CWE/CWE-079/CgiXss.qhelpCGI script vulnerable to cross-site scriptingDirectly writing an HTTP request parameter back to a web page allows for a cross-site scripting vulnerability. The data is displayed in a user's web browser as belonging to one site, but it is provided by some other site that the user browses to. In effect, such an attack allows one web site to insert content in the other one. For web servers implemented with the Common Gateway Interface (CGI), HTTP parameters are supplied via the RecommendationTo guard against cross-site scripting, consider escaping special characters before writing the HTTP parameter back to the page. ExampleIn the following example, the voidbad_server() {
char*query=getenv("QUERY_STRING");
puts("<p>Query results for ");
// BAD: Printing out an HTTP parameter with no escapingputs(query);
puts("\n<p>\n");
puts(do_search(query));
}
voidgood_server() {
char*query=getenv("QUERY_STRING");
puts("<p>Query results for ");
// GOOD: Escape HTML characters before adding to a pagechar*query_escaped=escape_html(query);
puts(query_escaped);
free(query_escaped);
puts("\n<p>\n");
puts(do_search(query));
}References
cpp/ql/src/Security/CWE/CWE-676/DangerousFunctionOverflow.qhelpUse of dangerous functionThis rule finds calls to the The RecommendationReplace calls to ExampleThe following example gets a string from standard input in two ways: #defineBUFFERSIZE (1024)
// BAD: using getsvoidecho_bad() {
charbuffer[BUFFERSIZE];
gets(buffer);
printf("Input was: '%s'\n", buffer);
}
// GOOD: using fgetsvoidecho_good() {
charbuffer[BUFFERSIZE];
fgets(buffer, BUFFERSIZE, stdin);
printf("Input was: '%s'\n", buffer);
}The first version uses Related rulesOther dangerous functions identified by CWE-676 ("Use of Potentially Dangerous Function") include References
cpp/ql/src/jsf/4.10 Classes/AV Rule 79.qhelpResource not released in destructorThis rule finds resources that are allocated by a class, but not released in the destructor of that class. Allocating a resource includes:
RecommendationIf the resource is not being released at all, ensure that the class does release the resource, normally by adding the release to the destructor of the class. This change needs to be carefully validated: client code may be relying on the resource outliving the class that allocated it, and must be reviewed and updated if necessary. In the other case, for instance a class that has an explicit
Example// This class opens a file but never closes it. Even its clients// cannot close the fileclassResourceLeak {
private:int sockfd;
FILE* file;
public:C() {
sockfd = socket(AF_INET, SOCK_STREAM, 0);
}
voidf() {
file = fopen("foo.txt", "r");
...
}
};
// This class relies on its client to release any stream it// allocates. Note that this means the client must have// intimate knowledge of the implementation of the class to// decide whether it is safe to release the stream. classStreamPool {
private:
Stream *instance;
public:
Stream *createStream(char *name) {
if (!instance) instance = newStream(name);
return instance;
}
}// This class handles its resources, but does not do that in// the constructor/destructor. It can be rewritten easily to// be safer to use.classStreamHandler {
private:char *_name;
Stream *stream;
public:C(char *name) {
_name = strdup(name):
}
voidopen() {
stream = newStream();
}
voidclose() {
delete stream;
}
~StreamHandler() {
free(_name);
// stream should be deleted here, not in close()
}
}References
csharp/ql/src/Bad Practices/CallsUnmanagedCode.qhelpCalls to unmanaged codeMicrosoft defines two broad categories for source code. Managed code compiles into bytecode and is then executed by a virtual machine. Unmanaged code is compiled directly into machine code. All C# code is managed but it is possible to call external unmanaged code. This rule finds calls to RecommendationConsider whether the calls could be replaced by calls to managed code instead. ExampleThis example shows a function that displays a message box when clicked. It is implemented with unmanaged code from the User32.dll library. usingSystem;usingSystem.Windows.Forms;usingSystem.Runtime.InteropServices;publicpartialclassUnmanagedCodeExample:Form{[DllImport("User32.dll")]publicstaticexternintMessageBox(inth,stringm,stringc,inttype);privatevoidbtnSayHello_Click(objectsender,EventArgse){MessageBox(0,"Hello World","Title",0);// BAD}}Fixing by Using Managed CodeThis code example does the exact same thing except it uses managed code to do so. usingSystem;usingSystem.Windows.Forms;publicpartialclassManagedCodeExample:Form{privatevoidbtnSayHello_Click(objectsender,EventArgse){MessageBox.Show("Hello World","Title");}}References
csharp/ql/src/Bad Practices/Comments/TodoComments.qhelpTODO commentA comment that includes the words RecommendationAddress the problem indicated by the comment. ExampleIn the following example, the programmer has not yet implemented the correct behavior for the case where parameter usingSystem;classBad{publicstaticdoubleSolveQuadratic(doublea,doubleb,doublec){// TODO: handle case where a == 0return(-b+Math.Sqrt(b*b-4*a*c))/(2*a);}}As a first step to fixing this problem, a check could be introduced that compares References
csharp/ql/src/Bad Practices/Declarations/EmptyInterface.qhelpEmpty interfaceEmpty interfaces are often used as a way of marking particular classes. RecommendationIn some languages, using a marker interface is a useful design pattern, but in C# it is better to use custom attributes. Marker interfaces are always inherited and so they cannot be applied to a single class without applying it to all subclasses. Custom attributes do not have this limitation. ExampleIn this example, the usingSystem;classBad{interfaceIsPrintable{}classForm1:IsPrintable{}}The following example is better because it uses attributes instead. usingSystem;classGood{[AttributeUsage(AttributeTargets.Class)]classPrintableAttribute:Attribute{}[Printable]classForm1{}}References
csharp/ql/src/Bad Practices/UnmanagedCodeCheck.qhelpUnmanaged codeMicrosoft defines two broad categories for source code. Managed code compiles into bytecode and is then executed by a virtual machine. Unmanaged code is compiled directly into machine code. All C# code is managed but it is possible to call external unmanaged code. This rule finds RecommendationConsider whether the unmanaged ExampleThis example shows a function that displays a message box when clicked. The unmanaged code is shown first and then the same function being performed by managed code is shown after. // example of using unmanaged codeusingSystem;usingSystem.Windows.Forms;usingSystem.Runtime.InteropServices;publicpartialclassUnmanagedCodeExample:Form{[DllImport("User32.dll")]publicstaticexternintMessageBox(inth,stringm,stringc,inttype);// BADprivatevoidbtnSayHello_Click(objectsender,EventArgse){MessageBox(0,"Hello World","Title",0);}}// the same thing in managed codeusingSystem;usingSystem.Windows.Forms;publicpartialclassManagedCodeExample:Form{privatevoidbtnSayHello_Click(objectsender,EventArgse){MessageBox.Show("Hello World","Title");}}References
csharp/ql/src/Dead Code/DeadStoreOfLocal.qhelpUseless assignment to local variableA value is assigned to a local variable, but either that variable is never read later on, or its value is always overwritten before being read. This means that the original assignment has no effect, and could indicate a logic error or incomplete code. RecommendationEnsure that you check the program logic carefully. If a value is really not needed, consider omitting the assignment. Be careful, though: if the right-hand side has a side effect (like performing a method call), it is important to keep this to preserve the overall behavior. ExampleThe following example shows six different types of assignments to local variables whose value is not read:
usingSystem;classBad{doubleParseInt(strings){varsuccess=int.TryParse(s,outinti);returni;}boolIsDouble(strings){varsuccess=double.TryParse(s,outdoublei);returnsuccess;}doubleParseDouble(strings){try{returndouble.Parse(s);}catch(FormatExceptione){returndouble.NaN;}}intCount(string[]ss){intcount=0;foreach(varsinss)count++;returncount;}stringIsInt(objecto){if(oisinti)return"yes";elsereturn"no";}stringIsString(objecto){switch(o){casestrings:return"yes";default:return"no";}}}The revised example eliminates the unread assignments. usingSystem;classGood{doubleParseInt(strings){int.TryParse(s,outinti);returni;}boolIsDouble(strings){varsuccess=double.TryParse(s,out_);returnsuccess;}doubleParseDouble(strings){try{returndouble.Parse(s);}catch(FormatException){returndouble.NaN;}}intCount(string[]ss){returnss.Length;}stringIsInt(objecto){if(oisint)return"yes";elsereturn"no";}stringIsString(objecto){switch(o){casestring _:return"yes";default:return"no";}}}References
csharp/ql/src/Likely Bugs/BadCheckOdd.qhelpBad parity checkAvoid using RecommendationConsider using Example-9 is an odd number but this example does not detect it as one. This is because classCheckOdd{privatestaticboolIsOdd(intx){returnx%2==1;}publicstaticvoidMain(String[]args){Console.Out.WriteLine(IsOdd(-9));// prints False}}It would be better to check if the number is even and then invert that check. classCheckOdd{privatestaticboolIsOdd(intx){returnx%2!=0;}publicstaticvoidMain(String[]args){Console.Out.WriteLine(IsOdd(-9));// prints True}}References
csharp/ql/src/Metrics/Callables/CCyclomaticComplexity.qhelpCyclomatic complexity of functionsThis metric measures the number of linearly independent execution paths through methods. Linearly independent paths are calculated using the control flow diagram for a piece of code. A linearly independent path includes at least one new edge that has not been included in any linearly independent path counted so far. Methods with a high cyclomatic complexity can be difficult to understand and difficult to test because there are so many different ways they could execute. Consider this method: publicstaticvoidfoo(intcount){if(count>10){Console.WriteLine("The count is large");}vartimesLeft=count;while(timesLeft>0){switch(Console.ReadLine()){case"BYE":Console.WriteLine("Good bye");break;case"HELLO":Console.WriteLine("Hi");break;case"HELP":Console.WriteLine("Try HELLO or BYE.");break;default:Console.WriteLine("Input not understood.");break;}timesLeft--;}}The control flow diagram for through this method looks like this:
RecommendationComplex methods should have parts of their functionality extracted to helper methods. This makes testing easier because each helper method can be tested individually. References
csharp/ql/src/Metrics/Files/FCyclomaticComplexity.qhelpAverage cyclomatic complexity of filesThis metric measures the average cyclomatic complexity of the functions in a file. The cyclomatic complexity of a function is the number of linearly independent execution paths through that function. A path is linearly independent path if it differs from all other paths by at least one node. Straight-line code therefore has a cyclomatic complexity of one, while branches, switches and loops increase cyclomatic complexity. Functions with a high cyclomatic complexity are typically hard to understand and test. By extension, files whose functions have a high average cyclomatic complexity are problematic, and usually would benefit from refactoring. As a concrete example, consider the following function: intf(inti,intj){// startintresult;if(i%2==0){// iEvenresult=i+j;}else{// iOddif(j%2==0){// jEvenresult=i*j;}else{// jOddresult=i-j;}}returnresult;// end}The control flow graph for this function is as follows:
RecommendationFunctions with a high cyclomatic complexity should be simplified, for instance by tidying up any complex logic within them or by splitting them into multiple methods using the Extract Method refactoring. References
csharp/ql/src/Metrics/Files/FSelfContainedness.qhelpSelf containedness of filesThis metric measures the percentage of types on which the file depends for which the build process built from source. The availability of source code is one of the key factors that affects how easy a project will be to build for different versions of the .NET framework. Files with low self-containedness are also more affected by changes to their dependencies. RecommendationDepending on your project, self-containedness may or may not be an issue for you. If you decide that it should be addressed then there are a few things you can do to easily increase self-containedness. One way of increasing self-containedness is by creating wrappers for any external classes. If the external class is changed then only your wrapper needs to be updated. You should also try to use libraries with source code available. References
csharp/ql/src/Metrics/RefTypes/TUnmanagedCode.qhelpTypes containing unmanaged codeMicrosoft defines two broad categories for source code. Managed code compiles into bytecode and is then executed by a virtual machine. Unmanaged code is compiled directly into machine code. All C# code is managed but it is possible to call external unmanaged code. This metric counts the number of RecommendationConsider whether the unmanaged methods could be replaced by managed code instead. ExampleThis example shows a function that displays a message box when clicked. It is implemented with unmanaged code from the usingSystem;usingSystem.Windows.Forms;usingSystem.Runtime.InteropServices;publicpartialclassUnmanagedCodeExample:Form{[DllImport("User32.dll")]publicstaticexternintMessageBox(inth,stringm,stringc,inttype);// violationprivatevoidbtnSayHello_Click(objectsender,EventArgse){MessageBox(0,"Hello World","Title",0);}}Fixing by Using Managed CodeThis example uses managed code to perform the same function. usingSystem;usingSystem.Windows.Forms;publicpartialclassManagedCodeExample:Form{privatevoidbtnSayHello_Click(objectsender,EventArgse){MessageBox.Show("Hello World","Title");}}References
csharp/ql/src/Security Features/CWE-079/XSS.qhelpCross-site scriptingDirectly writing user input (for example, an HTTP request parameter) to a webpage, without properly sanitizing the input first, allows for a cross-site scripting vulnerability. RecommendationTo guard against cross-site scripting, consider using a library that provides suitable encoding functionality, such as the ExampleThe following example shows the page parameter being written directly to the server error page, leaving the website vulnerable to cross-site scripting. usingSystem;usingSystem.Web;publicclassXSSHandler:IHttpHandler{publicvoidProcessRequest(HttpContextctx){ctx.Response.Write("The page \""+ctx.Request.QueryString["page"]+"\" was not found.");}}Sanitizing the user-controlled data using the usingSystem;usingSystem.Web;usingSystem.Net;publicclassXSSHandler:IHttpHandler{publicvoidProcessRequest(HttpContextctx){stringpage=WebUtility.HtmlEncode(ctx.Request.QueryString["page"]);ctx.Response.Write("The page \""+page+"\" was not found.");}}References
csharp/ql/src/Security Features/InadequateRSAPadding.qhelpWeak encryption: inadequate RSA paddingThis query finds uses of RSA encryption without secure padding. Using PKCS#1 v1.5 padding can open up your application to several different attacks resulting in the exposure of the encryption key or the ability to determine plaintext from encrypted messages. RecommendationUse the more secure PKCS#1 v2 (OAEP) padding. References
csharp/ql/src/Security Features/InsecureRandomness.qhelpInsecure randomnessUsing a cryptographically weak pseudo-random number generator to generate a security-sensitive value, such as a password, makes it easier for an attacker to predict the value. Pseudo-random number generators generate a sequence of numbers that only approximates the properties of random numbers. The sequence is not truly random because it is completely determined by a relatively small set of initial values, the seed. If the random number generator is cryptographically weak, then this sequence may be easily predictable through outside observations. RecommendationUse a cryptographically secure pseudo-random number generator if the output is to be used in a security sensitive context. As a rule of thumb, a value should be considered "security sensitive" if predicting it would allow the attacker to perform an action that they would otherwise be unable to perform. For example, if an attacker could predict the random password generated for a new user, they would be able to log in as that new user. For C#, ExampleThe following examples show different ways of generating a password. In the first case, we generate a fresh password by appending a random integer to the end of a static string. The random number generator used ( In the second example, a cryptographically secure random number generator is used for the same purpose. In this case, it is much harder to predict the generated integers. In the final example, the password is generated using the usingSystem.Security.Cryptography;usingSystem.Web.Security;stringGeneratePassword(){// BAD: Password is generated using a cryptographically insecure RNGRandomgen=newRandom();stringpassword="mypassword"+gen.Next();// GOOD: Password is generated using a cryptographically secure RNGusing(RNGCryptoServiceProvidercrypto=newRNGCryptoServiceProvider()){byte[]randomBytes=newbyte[sizeof(int)];crypto.GetBytes(randomBytes);password="mypassword"+BitConverter.ToInt32(randomBytes);}// BAD: Membership.GeneratePassword generates a password with a biaspassword=Membership.GeneratePassword(12,3);returnpassword;}References
csharp/ql/src/Security Features/InsufficientKeySize.qhelpWeak encryption: Insufficient key sizeThis rule finds uses of encryption algorithms with too small a key size. Encryption algorithms are vulnerable to brute force attack when too small a key size is used. RecommendationThe key should be at least 2048-bit long when using RSA encryption, and 128-bit long when using symmetric encryption. Referencescsharp/ql/src/Security Features/WeakEncryption.qhelpWeak encryptionWeak encryption algorithms provide very little security. For example DES encryption uses keys of 56 bits only, and no longer provides sufficient protection for sensitive data. TripleDES should also be deprecated for very sensitive data: Although it improves on DES by using 168-bit long keys, it provides in fact at most 112 bits of security. RecommendationYou should switch to a more secure encryption algorithm, such as AES (Advanced Encryption Standard) and use a key length which is reasonable for the application for which it is being used. Do not use the ECB encryption mode since it is vulnerable to replay and other attacks. ExampleThis example uses DES, which is limited to a 56-bit key. The key provided is actually 64 bits but the last bit of each byte is turned into a parity bit. For example the bytes 01010101 and 01010100 can be used in place of each other when encrypting and decrypting. classWeakEncryption{publicstaticbyte[]encryptString(){SymmetricAlgorithmserviceProvider=newDESCryptoServiceProvider();byte[]key={16,22,240,11,18,150,192,21};serviceProvider.Key=key;ICryptoTransformencryptor=serviceProvider.CreateEncryptor();Stringmessage="Hello World";byte[]messageB=System.Text.Encoding.ASCII.GetBytes(message);returnencryptor.TransformFinalBlock(messageB,0,messageB.Length);}}Referencesgo/ql/src/RedundantCode/DeadStoreOfLocal.qhelpUseless assignment to local variableA value is assigned to a variable, but either it is never read, or its value is always overwritten before being read. This means that the original assignment has no effect, and could indicate a logic error or incomplete code. RecommendationRemove assignments to variables that are immediately overwritten, or use the blank identifier ExampleIn the following example, a value is assigned to package main
import"fmt"funcmain() {
a:=calculateValue()
a=2b:=calculateValue()
ignore, ignore1:=fmt.Println(a)
ignore, ignore1, err:=function()
iferr!=nil {
panic(err)
}
fmt.Println(a)
}The result of package main
import"fmt"funcmain() {
a:=2fmt.Println(a)
_, _, err:=function()
iferr!=nil {
panic(err)
}
fmt.Println(a)
}References
go/ql/src/RedundantCode/UnreachableStatement.qhelpUnreachable statementAn unreachable statement often indicates missing code or a latent bug and should be examined carefully. RecommendationExamine the surrounding code to determine why the statement has become unreachable. If it is no longer needed, remove the statement. ExampleIn the following example, the body of the package main
funcmul(xs []int) int {
res:=1fori:=0; i<len(xs); i++ {
x:=xs[i]
res*=xifres==0 {
}
return0
}
returnres
}Most likely, the package main
funcmulGood(xs []int) int {
res:=1fori:=0; i<len(xs); i++ {
x:=xs[i]
res*=xifres==0 {
return0
}
}
returnres
}References
go/ql/src/Security/CWE-079/ReflectedXss.qhelpReflected cross-site scriptingDirectly writing user input (for example, an HTTP request parameter) to an HTTP response without properly sanitizing the input first, allows for a cross-site scripting vulnerability. This kind of vulnerability is also called reflected cross-site scripting, to distinguish it from other types of cross-site scripting. RecommendationTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the response, or one of the other solutions that are mentioned in the references. ExampleThe following example code writes part of an HTTP request (which is controlled by the user) directly to the response. This leaves the website vulnerable to cross-site scripting. package main
import (
"fmt""net/http"
)
funcserve() {
http.HandleFunc("/user", func(w http.ResponseWriter, r*http.Request) {
r.ParseForm()
username:=r.Form.Get("username")
if!isValidUsername(username) {
// BAD: a request parameter is incorporated without validation into the responsefmt.Fprintf(w, "%q is an unknown user", username)
} else {
// TODO: Handle successful login
}
})
http.ListenAndServe(":80", nil)
}Sanitizing the user-controlled data prevents the vulnerability: package main
import (
"fmt""html""net/http"
)
funcserve1() {
http.HandleFunc("/user", func(w http.ResponseWriter, r*http.Request) {
r.ParseForm()
username:=r.Form.Get("username")
if!isValidUsername(username) {
// GOOD: a request parameter is escaped before being put into the responsefmt.Fprintf(w, "%q is an unknown user", html.EscapeString(username))
} else {
// TODO: do something exciting
}
})
http.ListenAndServe(":80", nil)
}References
go/ql/src/Security/CWE-079/StoredXss.qhelpStored cross-site scriptingDirectly using externally-controlled stored values (for example, file names or database contents) to create HTML content without properly sanitizing the input first, allows for a cross-site scripting vulnerability. This kind of vulnerability is also called stored cross-site scripting, to distinguish it from other types of cross-site scripting. RecommendationTo guard against cross-site scripting, consider using contextual output encoding/escaping before using uncontrolled stored values to create HTML content, or one of the other solutions that are mentioned in the references. ExampleThe following example code writes file names directly to an HTTP response. This leaves the website vulnerable to cross-site scripting, if an attacker can choose the file names on the disk. package main
import (
"io""net/http""os"
)
funcListFiles(w http.ResponseWriter, r*http.Request) {
files, _:=os.ReadDir(".")
for_, file:=rangefiles {
io.WriteString(w, file.Name()+"\n")
}
}Sanitizing the file names prevents the vulnerability: package main
import (
"html""io""net/http""os"
)
funcListFiles1(w http.ResponseWriter, r*http.Request) {
files, _:=os.ReadDir(".")
for_, file:=rangefiles {
io.WriteString(w, html.EscapeString(file.Name())+"\n")
}
}References
go/ql/src/Security/CWE-338/InsecureRandomness.qhelpUse of insufficient randomness as the key of a cryptographic algorithmUsing a cryptographically weak pseudo-random number generator to generate a security-sensitive value, such as a password, makes it easier for an attacker to predict the value. Pseudo-random number generators generate a sequence of numbers that only approximates the properties of random numbers. The sequence is not truly random because it is completely determined by a relatively small set of initial values, the seed. If the random number generator is cryptographically weak, then this sequence may be easily predictable through outside observations. RecommendationUse a cryptographically secure pseudo-random number generator if the output is to be used in a security sensitive context. As a rule of thumb, a value should be considered "security sensitive" if predicting it would allow the attacker to perform an action that they would otherwise be unable to perform. For example, if an attacker could predict the random password generated for a new user, they would be able to log in as that new user. For Go, ExampleThe example below uses the package main
import (
"math/rand"
)
varcharset= []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
funcgeneratePassword() string {
s:=make([]rune, 20)
fori:=ranges {
s[i] =charset[rand.Intn(len(charset))]
}
returnstring(s)
}Instead, use package main
import (
"crypto/rand""math/big"
)
funcgeneratePasswordGood() string {
s:=make([]rune, 20)
fori:=ranges {
idx, err:=rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
iferr!=nil {
// handle err
}
s[i] =charset[idx.Int64()]
}
returnstring(s)
}References
java/ql/src/Likely Bugs/Concurrency/LazyInitStaticField.qhelpIncorrect lazy initialization of a static fieldThe tactic of initializing a static field the first time it is used, known as "lazy initialization", can be problematic in a multi-threaded context when used without proper synchronization. If a separate thread starts executing before the field is initialized, the thread may see an incompletely initialized object. RecommendationIf lazy initialization is desirable for performance reasons, the best solution is usually to declare the enclosing method ExampleIn the following example, the static field classSingleton {
privatestaticResourceresource;
publicResourcegetResource() {
if(resource == null)
resource = newResource(); // Lazily initialize "resource"returnresource;
}
}In the following modification of the above example, classSingleton {
privatestaticResourceresource;
static {
resource = newResource(); // Initialize "resource" only once
}
publicResourcegetResource() {
returnresource;
}
}References
java/ql/src/Metrics/Callables/CCyclomaticComplexity.qhelpCyclomatic complexity of functionsThe cyclomatic complexity of a method (or constructor) is the number of possible linearly-independent execution paths through that method (see [Wikipedia]). It was originally introduced as a complexity measure by Thomas McCabe [McCabe]. A method with high cyclomatic complexity is typically difficult to understand and test. Exampleintf(inti, intj) {
intresult;
if(i % 2 == 0) {
result = i + j;
}
else {
if(j % 2 == 0) {
result = i * j;
}
else {
result = i - j;
}
}
returnresult;
}The control flow graph for this method is as follows:
RecommendationSimplify methods that have a high cyclomatic complexity. For example, tidy up complex logic, and/or split methods into multiple smaller methods using the 'Extract Method' refactoring from [Fowler]. References
java/ql/src/Metrics/Files/FCyclomaticComplexity.qhelpAverage cyclomatic complexity of filesThis metric measures the average cyclomatic complexity of the functions in a file. The cyclomatic complexity of a function is the number of linearly independent execution paths through that function. A path is linearly independent path if it differs from all other paths by at least one node. Straight-line code therefore has a cyclomatic complexity of one, while branches, switches and loops increase cyclomatic complexity. Functions with a high cyclomatic complexity are typically hard to understand and test. By extension, files whose functions have a high average cyclomatic complexity are problematic, and usually would benefit from refactoring. As a concrete example, consider the following function: intf(inti, intj) {
// startintresult;
if(i % 2 == 0) {
// iEvenresult = i + j;
}
else {
// iOddif(j % 2 == 0) {
// jEvenresult = i * j;
}
else {
// jOddresult = i - j;
}
}
returnresult;
// end
}The control flow graph for this function is as follows:
RecommendationFunctions with a high cyclomatic complexity should be simplified, for instance by tidying up any complex logic within them or by splitting them into multiple methods using the Extract Method refactoring. References
java/ql/src/Metrics/Files/FLinesOfDuplicatedCode.qhelpDuplicated lines in filesThis metric measures the number of lines in a file that are contained within a block that is duplicated elsewhere. These lines may include code, comments and whitespace, and the duplicate block may be in this file or in another file. A file that contains many lines that are duplicated within the code base is problematic for a number of reasons. Duplicated code increases overall code size, making the code base harder to maintain and harder to understand. It also becomes harder to fix bugs, since a programmer applying a fix to one copy has to always remember to update other copies accordingly. Finally, code duplication is generally an indication of a poorly designed or hastily written code base, which typically suffers from other problems as well. RecommendationRefactor files with lots of duplicated code to extract the common code into a shared library or module. References
java/ql/src/Metrics/Files/FLinesOfSimilarCode.qhelpSimilar lines in filesA file that contains many lines that are similar to other code within the code base is problematic for the same reasons as a file that contains a lot of (exactly) duplicated code. Duplicated code increases overall code size, making the code base harder to maintain and harder to understand. It also becomes harder to fix bugs, since a programmer applying a fix to one copy has to always remember to update other copies accordingly. Finally, code duplication is generally an indication of a poorly designed or hastily written code base, which typically suffers from other problems as well. RecommendationRefactor similar code snippets by extracting common functionality into methods that can be reused across classes. References
java/ql/src/Metrics/Files/FSelfContainedness.qhelpSelf-containedness of filesThis metric measures the percentage of the types on which a compilation unit depends for which we have source code available. The availability of source code is one of the key factors affecting how easy or difficult it will be to build a software project in the future, especially on platforms other than those for which it was originally developed. Projects will a high level of self-containedness are likely to be more portable and easier to build in ten years' time than those that depend on many binary-only, third-party libraries. (This is one reason why many of the dependencies of open-source projects are distributed as source code, aside from the fact that the binaries are generally larger and more unwieldy to distribute.) In the context of Java's platform independence, the availability of source code is less critical than it is for platform-dependent languages. However, note that there can be minor binary incompatibilities between different versions of Java. RecommendationLow self-containedness may or may not be a problem, depending on the context of your project. However, if you determine that it is an issue for you, it is best tackled at a project level, in the following ways:
References
java/ql/src/Metrics/RefTypes/TSelfContainedness.qhelpSelf-containedness of typesThis metric measures the percentage of the types on which a type depends for which we have source code available. The availability of source code is one of the key factors affecting how easy or difficult it will be to build a software project in the future, especially on platforms other than those for which it was originally developed. Projects will a high level of self-containedness are likely to be more portable and easier to build in ten years' time than those that depend on many binary-only, third-party libraries. (This is one reason why many of the dependencies of open-source projects are distributed as source code, aside from the fact that the binaries are generally larger and more unwieldy to distribute.) In the context of Java's platform independence, the availability of source code is less critical than it is for platform-dependent languages. However, note that there can be minor binary incompatibilities between different versions of Java. RecommendationLow self-containedness may or may not be a problem, depending on the context of your project. However, if you determine that it is an issue for you, it is best tackled at a project level, in the following ways:
References
java/ql/src/Security/CWE/CWE-079/XSS.qhelpCross-site scriptingDirectly writing user input (for example, an HTTP request parameter) to a web page, without properly sanitizing the input first, allows for a cross-site scripting vulnerability. RecommendationTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the reference. ExampleThe following example shows the publicclassXSSextendsHttpServlet {
protectedvoiddoGet(HttpServletRequestrequest, HttpServletResponseresponse)
throwsServletException, IOException {
// BAD: a request parameter is written directly to the Servlet response streamresponse.getWriter().print(
"The page \"" + request.getParameter("page") + "\" was not found.");
}
}References
java/ql/src/Security/CWE/CWE-113/ResponseSplitting.qhelpHTTP response splittingDirectly writing user input (for example, an HTTP request parameter) to an HTTP header can lead to an HTTP request-splitting or response-splitting vulnerability. HTTP response splitting can lead to vulnerabilities such as XSS and cache poisoning. HTTP request splitting can allow an attacker to inject an additional HTTP request into a client's outgoing socket connection. This can allow an attacker to perform an SSRF-like attack. In the context of a servlet container, if the user input includes blank lines and the servlet container does not escape the blank lines, then a remote user can cause the response to turn into two separate responses. The remote user can then control one or more responses, which is also HTTP response splitting. RecommendationGuard against HTTP header splitting in the same way as guarding against cross-site scripting. Before passing any data into HTTP headers, either check the data for special characters, or escape any special characters that are present. If the code calls Netty API's directly, ensure that the ExampleThe following example shows the 'name' parameter being written to a cookie in two different ways. The first way writes it directly to the cookie, and thus is vulnerable to response-splitting attacks. The second way first removes all special characters, thus avoiding the potential problem. publicclassResponseSplittingextendsHttpServlet {
protectedvoiddoGet(HttpServletRequestrequest, HttpServletResponseresponse)
throwsServletException, IOException {
// BAD: setting a cookie with an unvalidated parameterCookiecookie = newCookie("name", request.getParameter("name"));
response.addCookie(cookie);
// GOOD: remove special characters before putting them in the headerStringname = removeSpecial(request.getParameter("name"));
Cookiecookie2 = newCookie("name", name);
response.addCookie(cookie2);
}
privatestaticStringremoveSpecial(Stringstr) {
returnstr.replaceAll("[^a-zA-Z ]", "");
}
}ExampleThe following example shows the use of the library 'netty' with HTTP response-splitting verification configurations. The second way will verify the parameters before using them to build the HTTP response. importio.netty.handler.codec.http.DefaultHttpHeaders;
publicclassResponseSplitting {
// BAD: Disables the internal response splitting verificationprivatefinalDefaultHttpHeadersbadHeaders = newDefaultHttpHeaders(false);
// GOOD: Verifies headers passed don't contain CRLF charactersprivatefinalDefaultHttpHeadersgoodHeaders = newDefaultHttpHeaders();
// BAD: Disables the internal response splitting verificationprivatefinalDefaultHttpResponsebadResponse = newDefaultHttpResponse(version, httpResponseStatus, false);
// GOOD: Verifies headers passed don't contain CRLF charactersprivatefinalDefaultHttpResponsegoodResponse = newDefaultHttpResponse(version, httpResponseStatus);
}ExampleThe following example shows the use of the netty library with configurations for verification of HTTP request splitting. The second recommended approach in the example verifies the parameters before using them to build the HTTP request. publicclassNettyRequestSplitting {
// BAD: Disables the internal request splitting verificationprivatefinalDefaultHttpHeadersbadHeaders = newDefaultHttpHeaders(false);
// GOOD: Verifies headers passed don't contain CRLF charactersprivatefinalDefaultHttpHeadersgoodHeaders = newDefaultHttpHeaders();
// BAD: Disables the internal request splitting verificationprivatefinalDefaultHttpRequestbadRequest = newDefaultHttpRequest(httpVersion, method, uri, false);
// GOOD: Verifies headers passed don't contain CRLF charactersprivatefinalDefaultHttpRequestgoodResponse = newDefaultHttpRequest(httpVersion, method, uri);
}References
java/ql/src/Security/CWE/CWE-326/InsufficientKeySize.qhelpUse of a cryptographic algorithm with insufficient key sizeModern encryption relies on the computational infeasibility of breaking a cipher and decoding its message without the key. As computational power increases, the ability to break ciphers grows, and key sizes need to become larger as a result. Cryptographic algorithms that use too small of a key size are vulnerable to brute force attacks, which can reveal sensitive data. RecommendationUse a key of the recommended size or larger. The key size should be at least 128 bits for AES encryption, 256 bits for elliptic-curve cryptography (ECC), and 2048 bits for RSA, DSA, or DH encryption. ExampleThe following code uses cryptographic algorithms with insufficient key sizes. KeyPairGeneratorkeyPairGen1 = KeyPairGenerator.getInstance("RSA");
keyPairGen1.initialize(1024); // BAD: Key size is less than 2048KeyPairGeneratorkeyPairGen2 = KeyPairGenerator.getInstance("DSA");
keyPairGen2.initialize(1024); // BAD: Key size is less than 2048KeyPairGeneratorkeyPairGen3 = KeyPairGenerator.getInstance("DH");
keyPairGen3.initialize(1024); // BAD: Key size is less than 2048KeyPairGeneratorkeyPairGen4 = KeyPairGenerator.getInstance("EC");
ECGenParameterSpececSpec = newECGenParameterSpec("secp112r1"); // BAD: Key size is less than 256keyPairGen4.initialize(ecSpec);
KeyGeneratorkeyGen = KeyGenerator.getInstance("AES");
keyGen.init(64); // BAD: Key size is less than 128To fix the code, change the key sizes to be the recommended size or larger for each algorithm. References
java/ql/src/Security/CWE/CWE-330/InsecureRandomness.qhelpInsecure randomnessIf you use a cryptographically weak pseudo-random number generator to generate security-sensitive values, such as passwords, attackers can more easily predict those values. Pseudo-random number generators generate a sequence of numbers that only approximates the properties of random numbers. The sequence is not truly random because it is completely determined by a relatively small set of initial values (the seed). If the random number generator is cryptographically weak, then this sequence may be easily predictable through outside observations. RecommendationThe Use a cryptographically secure pseudo-random number generator if the output is to be used in a security-sensitive context. As a general rule, a value should be considered "security-sensitive" if predicting it would allow the attacker to perform an action that they would otherwise be unable to perform. For example, if an attacker could predict the random password generated for a new user, they would be able to log in as that new user. ExampleThe following examples show different ways of generating a cookie with a random value. In the first (BAD) case, we generate a fresh cookie by appending a random integer to the end of a static string. The random number generator used ( Randomr = newRandom(); // BAD: Random is not cryptographically securebyte[] bytes = newbyte[16];
r.nextBytes(bytes);
StringcookieValue = encode(bytes);
Cookiecookie = newCookie("name", cookieValue);
response.addCookie(cookie);In the second (GOOD) case, we generate a fresh cookie by appending a random integer to the end of a static string. The random number generator used ( SecureRandomr = newSecureRandom(); // GOOD: SecureRandom is cryptographically securebyte[] bytes = newbyte[16];
r.nextBytes(bytes);
StringcookieValue = encode(bytes);
Cookiecookie = newCookie("name", cookieValue);
response.addCookie(cookie);References
java/ql/src/Security/CWE/CWE-501/TrustBoundaryViolation.qhelpTrust boundary violationA trust boundary violation occurs when a value is passed from a less trusted context to a more trusted context. For example, a value that is generated by a less trusted source, such as a user, may be passed to a more trusted source, such as a system process. If the less trusted source is malicious, then the value may be crafted to exploit the more trusted source. Trust boundary violations are often caused by a failure to validate input. For example, if a web application accepts a cookie from a user, then the application should validate the cookie before using it. If the cookie is not validated, then the user may be able to craft a malicious cookie that exploits the application. RecommendationTo maintain a trust boundary, validate data from less trusted sources before use. ExampleIn the first (bad) example, the server accepts a parameter from the user, then uses it to set the username without validation. publicvoiddoGet(HttpServletRequestrequest, HttpServletResponseresponse) {
Stringusername = request.getParameter("username");
// BAD: The input is written to the session without being sanitized.request.getSession().setAttribute("username", username);
}In the second (good) example, the server validates the parameter from the user, then uses it to set the username. publicvoiddoGet(HttpServletRequestrequest, HttpServletResponseresponse) {
Stringusername = request.getParameter("username");
if (validator.isValidInput("HTTP parameter", username, "username", 20, false)) {
// GOOD: The input is sanitized before being written to the session.request.getSession().setAttribute("username", username);
}
}References
java/ql/src/Violations of Best Practice/Comments/TodoComments.qhelpTODO/FIXME commentsA comment that includes the word For example, this list of comments is typical of those found in real programs:
RecommendationIt is very important that Simpler comments can usually be immediately addressed by fixing the code, adding a test, doing some refactoring, or clarifying the intended behavior of a feature. In contrast, larger issues may require discussion, and a significant amount of work to address. In these cases it is a good idea to move the comment to an issue-tracking system, so that the issue can be tracked and prioritized relative to other defects and feature requests. References
java/ql/src/Violations of Best Practice/Dead Code/DeadRefTypes.qhelpUnused classes and interfacesA non-public class or interface that is not used anywhere in the program may cause a programmer to waste time and effort maintaining and documenting it. RecommendationEnsure that redundant types are removed from the program. References
javascript/ql/src/Comments/TodoComments.qhelpTODO commentA comment that includes the words RecommendationAddress the problem indicated by the comment. ExampleIn the following example, the programmer has not yet implemented the correct behavior for the case where parameter functionsolveQuadratic(a,b,c){// TODO: handle case where a === 0return(-b+Math.sqrt(b*b-4*a*c))/(2*a);}As a first step to fixing this problem, a check could be introduced that compares References
javascript/ql/src/Declarations/DeadStoreOfLocal.qhelpUseless assignment to local variableA value is assigned to a variable or property, but either that location is never read later on, or its value is always overwritten before being read. This means that the original assignment has no effect, and could indicate a logic error or incomplete code. RecommendationEnsure that you check the control and data flow in the method carefully. If a value is really not needed, consider omitting the assignment. Be careful, though: if the right-hand side has a side-effect (like performing a method call), it is important to keep this to preserve the overall behavior. ExampleIn the following example, the return value of the call to functionf(x){varresult=send(x);waitForResponse();returngetResponse();}Assuming that functionf(x){varresult=send(x);// check for errorif(result===-1)thrownewError("send failed");waitForResponse();returngetResponse();}References
javascript/ql/src/Declarations/DeadStoreOfProperty.qhelpUseless assignment to propertyA value is assigned to a variable or property, but either that location is never read later on, or its value is always overwritten before being read. This means that the original assignment has no effect, and could indicate a logic error or incomplete code. RecommendationEnsure that you check the control and data flow in the method carefully. If a value is really not needed, consider omitting the assignment. Be careful, though: if the right-hand side has a side-effect (like performing a method call), it is important to keep this to preserve the overall behavior. ExampleIn the following example, the return value of the call to functionf(x){varresult=send(x);waitForResponse();returngetResponse();}Assuming that functionf(x){varresult=send(x);// check for errorif(result===-1)thrownewError("send failed");waitForResponse();returngetResponse();}References
javascript/ql/src/LanguageFeatures/Eval.qhelpUse of evalThe built-in RecommendationThere are few genuine uses of ExampleIn the following example, functionPoint(x,y){this.x=x;this.y=y;}["x","y"].forEach(function(p){eval("Point.prototype.get_"+p+" = function() {"+" return this."+p+";"+"}");eval("Point.prototype.set_"+p+" = function(v) {"+" if (typeof v !== 'number')"+" throw Error('number expected');"+" this."+p+" = v;"+"}");});In a variant, the programmer has realized that they can use computed property accesses to avoid having to wrap the assignment into an functionPoint(x,y){this.x=x;this.y=y;}["x","y"].forEach(function(p){Point.prototype["get_"+p]=newFunction("","return this."+p+";");Point.prototype["set_"+p]=newFunction("v","if (typeof v !== 'number')"+" throw Error('number expected');"+" this."+p+" = v;");});This is not necessary either as the following example shows, where the use of functionPoint(x,y){this.x=x;this.y=y;}["x","y"].forEach(function(p){Point.prototype["get_"+p]=function(){returnthis[p];};Point.prototype["set_"+p]=function(v){if(typeofv!=='number')throwError('number expected');this[p]=v;};});References
javascript/ql/src/Metrics/FCyclomaticComplexity.qhelpAverage cyclomatic complexity of filesThis metric measures the average cyclomatic complexity of the functions in a file. The cyclomatic complexity of a function is the number of linearly independent execution paths through that function. A path is linearly independent path if it differs from all other paths by at least one node. Straight-line code therefore has a cyclomatic complexity of one, while branches, switches and loops increase cyclomatic complexity. Functions with a high cyclomatic complexity are typically hard to understand and test. By extension, files whose functions have a high average cyclomatic complexity are problematic, and usually would benefit from refactoring. As a concrete example, consider the following function: functionf(i,j){// startvarresult;if(i%2==0){// iEvenresult=i+j;}else{// iOddif(j%2==0){// jEvenresult=i*j;}else{// jOddresult=i-j;}}returnresult;// end}The control flow graph for this function is as follows:
RecommendationFunctions with a high cyclomatic complexity should be simplified, for instance by tidying up any complex logic within them or by splitting them into multiple methods using the Extract Method refactoring. References
javascript/ql/src/Metrics/FLinesOfDuplicatedCode.qhelpDuplicated lines in filesThis metric measures the number of lines in a file that are contained within a block that is duplicated elsewhere. These lines may include code, comments and whitespace, and the duplicate block may be in this file or in another file. A file that contains many lines that are duplicated within the code base is problematic for a number of reasons. Duplicated code increases overall code size, making the code base harder to maintain and harder to understand. It also becomes harder to fix bugs, since a programmer applying a fix to one copy has to always remember to update other copies accordingly. Finally, code duplication is generally an indication of a poorly designed or hastily written code base, which typically suffers from other problems as well. RecommendationRefactor files with lots of duplicated code to extract the common code into a shared library or module. References
javascript/ql/src/Metrics/FLinesOfSimilarCode.qhelpSimilar lines in filesThis metric measures the number of lines in a file that are contained within a block that is duplicated elsewhere. These lines may include code, comments and whitespace, and the duplicate block may be in this file or in another file. A file that contains many lines that are similar to other code within the code base is problematic for the same reasons as a file that contains a lot of (exactly) duplicated code. Duplicated code increases overall code size, making the code base harder to maintain and harder to understand. It also becomes harder to fix bugs, since a programmer applying a fix to one copy has to always remember to update other copies accordingly. Finally, code duplication is generally an indication of a poorly designed or hastily written code base, which typically suffers from other problems as well. RecommendationRefactor similar code snippets by extracting common functionality into functions that can be reused across modules. References
javascript/ql/src/Metrics/FunCyclomaticComplexity.qhelpCyclomatic complexity of functionsThis metric measures the cyclomatic complexity of each function in the project. The cyclomatic complexity of a function is an indication of the number of paths that can be taken during the execution of a function. Code with many branches and loops has high cyclomatic complexity. A cyclomatic complexity above 50 should be considered bad practice and above 75 should definitely be addressed. Functions with high cyclomatic complexity are
RecommendationThe primary way to reduce the complexity is to extract sub-functionality into separate functions. This improves on all problems described above. If the function naturally breaks up into a sequence of operations it is preferable to extract each operation as a separate function. Even if that's not the case it is often possible to extract the body of an iteration into a separate function to reduce complexity. If the complexity can't be reduced significantly make sure that the function is properly documented and carefully tested. References
javascript/ql/src/Security/CWE-079/ExceptionXss.qhelpException text reinterpreted as HTMLDirectly writing error messages to a webpage without sanitization allows for a cross-site scripting vulnerability if parts of the error message can be influenced by a user. RecommendationTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the references. ExampleThe following example shows an exception being written directly to the document, and this exception can potentially be influenced by the page URL, leaving the website vulnerable to cross-site scripting. functionsetLanguageOptions(){varhref=document.location.href,deflt=href.substring(href.indexOf("default=")+8);try{varparsed=unknownParseFunction(deflt);}catch(e){document.write("Had an error: "+e+".");}}ExampleThis second example shows an input being validated using the JSON schema validator importexpressfrom'express';importAjvfrom'ajv';letapp=express();letajv=newAjv();ajv.addSchema({type: 'object',additionalProperties: {type: 'number'}},'pollData');app.post('/polldata',(req,res)=>{if(!ajv.validate('pollData',req.body)){res.send(ajv.errorsText());}});This is unsafe, because the error message can contain parts of the input. For example, the input References
javascript/ql/src/Security/CWE-079/ReflectedXss.qhelpReflected cross-site scriptingDirectly writing user input (for example, an HTTP request parameter) to an HTTP response without properly sanitizing the input first, allows for a cross-site scripting vulnerability. This kind of vulnerability is also called reflected cross-site scripting, to distinguish it from other types of cross-site scripting. RecommendationTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the response, or one of the other solutions that are mentioned in the references. ExampleThe following example code writes part of an HTTP request (which is controlled by the user) directly to the response. This leaves the website vulnerable to cross-site scripting. varapp=require('express')();app.get('/user/:id',function(req,res){if(!isValidUserId(req.params.id))// BAD: a request parameter is incorporated without validation into the responseres.send("Unknown user: "+req.params.id);else// TODO: do something exciting;});Sanitizing the user-controlled data prevents the vulnerability: varescape=require('escape-html');varapp=require('express')();app.get('/user/:id',function(req,res){if(!isValidUserId(req.params.id))// GOOD: request parameter is sanitized before incorporating it into the responseres.send("Unknown user: "+escape(req.params.id));else// TODO: do something exciting;});References
javascript/ql/src/Security/CWE-079/StoredXss.qhelpStored cross-site scriptingDirectly using uncontrolled stored value (for example, file names) to create HTML content without properly sanitizing the input first, allows for a cross-site scripting vulnerability. This kind of vulnerability is also called stored cross-site scripting, to distinguish it from other types of cross-site scripting. RecommendationTo guard against cross-site scripting, consider using contextual output encoding/escaping before using uncontrolled stored values to create HTML content, or one of the other solutions that are mentioned in the references. ExampleThe following example code writes file names directly to a HTTP response. This leaves the website vulnerable to cross-site scripting, if an attacker can choose the file names on the disk. varexpress=require('express'),fs=require('fs');express().get('/list-directory',function(req,res){fs.readdir('/public',function(error,fileNames){varlist='<ul>';fileNames.forEach(fileName=>{// BAD: `fileName` can contain HTML elementslist+='<li>'+fileName+'</li>';});list+='</ul>'res.send(list);});});Sanitizing the file names prevents the vulnerability: varexpress=require('express'),fs=require('fs'),escape=require('escape-html');express().get('/list-directory',function(req,res){fs.readdir('/public',function(error,fileNames){varlist='<ul>';fileNames.forEach(fileName=>{// GOOD: escaped `fileName` can not contain HTML elementslist+='<li>'+escape(fileName)+'</li>';});list+='</ul>'res.send(list);});});References
javascript/ql/src/Security/CWE-079/UnsafeHtmlConstruction.qhelpUnsafe HTML constructed from library inputWhen a library function dynamically constructs HTML in a potentially unsafe way, then it's important to document to clients of the library that the function should only be used with trusted inputs. If the function is not documented as being potentially unsafe, then a client may inadvertently use inputs containing unsafe HTML fragments, and thereby leave the client vulnerable to cross-site scripting attacks. RecommendationDocument all library functions that can lead to cross-site scripting attacks, and guard against unsafe inputs where dynamic HTML construction is not intended. ExampleThe following example has a library function that renders a boldface name by writing to the module.exports=functionshowBoldName(name){document.getElementById('name').innerHTML="<b>"+name+"</b>";}This library function, however, does not escape unsafe HTML, and a client that calls the function with user-supplied input may be vulnerable to cross-site scripting attacks. The library could either document that this function should not be used with unsafe inputs, or use safe APIs such as module.exports=functionshowBoldName(name){constbold=document.createElement('b');bold.innerText=name;document.getElementById('name').appendChild(bold);}Alternatively, an HTML sanitizer can be used to remove unsafe content. conststriptags=require('striptags');module.exports=functionshowBoldName(name){document.getElementById('name').innerHTML="<b>"+striptags(name)+"</b>";}References
javascript/ql/src/Security/CWE-079/UnsafeJQueryPlugin.qhelpUnsafe jQuery pluginLibrary plugins, such as those for the jQuery library, are often configurable through options provided by the clients of the plugin. Clients, however, do not know the implementation details of the plugin, so it is important to document the capabilities of each option. The documentation for the plugin options that the client is responsible for sanitizing is of particular importance. Otherwise, the plugin may write user input (for example, a URL query parameter) to a web page without properly sanitizing it first, which allows for a cross-site scripting vulnerability in the client application through dynamic HTML construction. RecommendationDocument all options that can lead to cross-site scripting attacks, and guard against unsafe inputs where dynamic HTML construction is not intended. ExampleThe following example shows a jQuery plugin that selects a DOM element, and copies its text content to another DOM element. The selection is performed by using the plugin option jQuery.fn.copyText=function(options){// BAD may evaluate `options.sourceSelector` as HTMLvarsource=jQuery(options.sourceSelector),text=source.text();jQuery(this).text(text);}This is, however, not a safe plugin, since the call to Instead of documenting that the client is responsible for sanitizing jQuery.fn.copyText=function(options){// GOOD may not evaluate `options.sourceSelector` as HTMLvarsource=jQuery.find(options.sourceSelector),text=source.text();jQuery(this).text(text);}References
javascript/ql/src/Security/CWE-079/Xss.qhelpClient-side cross-site scriptingDirectly writing user input (for example, a URL query parameter) to a webpage without properly sanitizing the input first, allows for a cross-site scripting vulnerability. This kind of vulnerability is also called DOM-based cross-site scripting, to distinguish it from other types of cross-site scripting. RecommendationTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the references. ExampleThe following example shows part of the page URL being written directly to the document, leaving the website vulnerable to cross-site scripting. functionsetLanguageOptions(){varhref=document.location.href,deflt=href.substring(href.indexOf("default=")+8);document.write("<OPTION value=1>"+deflt+"</OPTION>");document.write("<OPTION value=2>English</OPTION>");}References
javascript/ql/src/Security/CWE-079/XssThroughDom.qhelpDOM text reinterpreted as HTMLExtracting text from a DOM node and interpreting it as HTML can lead to a cross-site scripting vulnerability. A webpage with this vulnerability reads text from the DOM, and afterwards adds the text as HTML to the DOM. Using text from the DOM as HTML effectively unescapes the text, and thereby invalidates any escaping done on the text. If an attacker is able to control the safe sanitized text, then this vulnerability can be exploited to perform a cross-site scripting attack. RecommendationTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing text to the page, or one of the other solutions that are mentioned in the References section below. ExampleThe following example shows a webpage using a $("button").click(function(){vartarget=$(this).attr("data-target");$(target).hide();});However, if an attacker can control the The above vulnerability can be fixed by using $("button").click(function(){vartarget=$(this).attr("data-target");$.find(target).hide();});References
javascript/ql/src/Security/CWE-116/IncompleteHtmlAttributeSanitization.qhelpIncomplete HTML attribute sanitizationSanitizing untrusted input for HTML meta-characters is a common technique for preventing cross-site scripting attacks. Usually, this is done by escaping As a consequence, some programs only sanitize RecommendationSanitize all relevant HTML meta-characters when constructing HTML dynamically, and pay special attention to where the sanitized value is used. An even safer alternative is to design the application so that sanitization is not needed, for instance by using HTML templates that are explicit about the values they treat as HTML. ExampleThe following example code writes part of an HTTP request (which is controlled by the user) to an HTML attribute of the server response. The user-controlled value is, however, not sanitized for varapp=require('express')();app.get('/user/:id',function(req,res){letid=req.params.id;id=id.replace(/<|>/g,"");// BADletuserHtml=`<div data-id="${id}">${getUserName(id)||"Unknown name"}</div>`;// ...res.send(prefix+userHtml+suffix);});Sanitizing the user-controlled data for varapp=require('express')();app.get('/user/:id',function(req,res){letid=req.params.id;id=id.replace(/<|>|&|"/g,"");// GOODletuserHtml=`<div data-id="${id}">${getUserName(id)||"Unknown name"}</div>`;// ...res.send(prefix+userHtml+suffix);});References
javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelpUnsafe expansion of self-closing HTML tagSanitizing untrusted input for HTML meta-characters is a common technique for preventing cross-site scripting attacks. But even a sanitized input can be dangerous to use if it is modified further before a browser treats it as HTML. A seemingly innocent transformation that expands a self-closing HTML tag from RecommendationUse a well-tested sanitization library if at all possible, and avoid modifying sanitized values further before treating them as HTML. An even safer alternative is to design the application so that sanitization is not needed, for instance by using HTML templates that are explicit about the values they treat as HTML. ExampleThe following function transforms a self-closing HTML tag to a pair of open/close tags. It does so for all non- functionexpandSelfClosingTags(html){varrxhtmlTag=/<(?!img|area)(([a-z][^\w\/>]*)[^>]*)\/>/gi;returnhtml.replace(rxhtmlTag,"<$1></$2>");// BAD}While it is generally known regular expressions are ill-suited for parsing HTML, variants of this particular transformation pattern have long been considered safe. However, the function is not safe. As an example, consider the following string: <divalt="<x" title="/><img src=url404 onerror=alert(1)>"/>When the above function transforms the string, it becomes a string that results in an alert when a browser treats it as HTML. <divalt="<x" title="></x" ><imgsrc=url404onerror=alert(1)>"/>References
javascript/ql/src/Security/CWE-338/InsecureRandomness.qhelpInsecure randomnessUsing a cryptographically weak pseudo-random number generator to generate a security-sensitive value, such as a password, makes it easier for an attacker to predict the value. Pseudo-random number generators generate a sequence of numbers that only approximates the properties of random numbers. The sequence is not truly random because it is completely determined by a relatively small set of initial values, the seed. If the random number generator is cryptographically weak, then this sequence may be easily predictable through outside observations. RecommendationUse a cryptographically secure pseudo-random number generator if the output is to be used in a security-sensitive context. As a rule of thumb, a value should be considered "security-sensitive" if predicting it would allow the attacker to perform an action that they would otherwise be unable to perform. For example, if an attacker could predict the random password generated for a new user, they would be able to log in as that new user. For JavaScript on the NodeJS platform, For JavaScript in the browser, ExampleThe following examples show different ways of generating a password. In the first case, we generate a fresh password by appending a random integer to the end of a static string. The random number generator used ( functioninsecurePassword(){// BAD: the random suffix is not cryptographically securevarsuffix=Math.random();varpassword="myPassword"+suffix;returnpassword;}In the second example, a cryptographically secure random number generator is used for the same purpose. In this case, it is much harder to predict the generated integers. functionsecurePassword(){// GOOD: the random suffix is cryptographically securevarsuffix=window.crypto.getRandomValues(newUint32Array(1))[0];varpassword="myPassword"+suffix;// GOOD: if a random value between 0 and 1 is desiredvarsecret=window.crypto.getRandomValues(newUint32Array(1))[0]*Math.pow(2,-32);}References
javascript/ql/src/Statements/DanglingElse.qhelpMisleading indentation of dangling 'else'In JavaScript, an Indenting the RecommendationEnsure that matching ExampleIn the following example, the functionf(){if(cond1())if(cond2())return23;elsereturn42;return56;}To correct this issue, indent the functionf(){if(cond1())if(cond2())return23;elsereturn42;return56;}Confusion about which functionf(){if(cond1()){if(cond2()){return23;}else{return42;}}return56;}References
javascript/ql/src/Statements/UnreachableStatement.qhelpUnreachable statementAn unreachable statement almost always indicates missing code or a latent bug and should be examined carefully. RecommendationExamine the surrounding code to determine why the statement has become unreachable. If it is no longer needed, remove the statement. ExampleIn the following example, a spurious semicolon after the functionf(){if(someCond());return23;return42;}To correct this issue, remove the spurious semicolon: functionf(){if(someCond())return23;return42;}References
javascript/ql/src/experimental/heuristics/ql/src/Security/CWE-079/Xss.qhelpClient-side cross-site scripting with additional heuristic sourcesDirectly writing user input (for example, a URL query parameter) to a webpage without properly sanitizing the input first, allows for a cross-site scripting vulnerability. This kind of vulnerability is also called DOM-based cross-site scripting, to distinguish it from other types of cross-site scripting. RecommendationTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the references. ExampleThe following example shows part of the page URL being written directly to the document, leaving the website vulnerable to cross-site scripting. functionsetLanguageOptions(){varhref=document.location.href,deflt=href.substring(href.indexOf("default=")+8);document.write("<OPTION value=1>"+deflt+"</OPTION>");document.write("<OPTION value=2>English</OPTION>");}References
python/ql/src/Metrics/FLinesOfDuplicatedCode.qhelpDuplicated lines in filesThis metric measures the number of lines in a file that are contained within a block that is duplicated elsewhere. These lines may include code, comments and whitespace, and the duplicate block may be in this file or in another file. A file that contains many lines that are duplicated within the code base is problematic for a number of reasons. Duplicated code increases overall code size, making the code base harder to maintain and harder to understand. It also becomes harder to fix bugs, since a programmer applying a fix to one copy has to always remember to update other copies accordingly. Finally, code duplication is generally an indication of a poorly designed or hastily written code base, which typically suffers from other problems as well. RecommendationRefactor files with lots of duplicated code to extract the common code into a shared library or module. References
ruby/ql/src/experimental/insecure-randomness/InsecureRandomness.qhelpInsecure randomnessUsing a cryptographically weak pseudo-random number generator to generate a security-sensitive value, such as a password, makes it easier for an attacker to predict the value. Pseudo-random number generators generate a sequence of numbers that only approximates the properties of random numbers. The sequence is not truly random because it is completely determined by a relatively small set of initial values, the seed. If the random number generator is cryptographically weak, then this sequence may be easily predictable through outside observations. RecommendationWhen generating values for use in security-sensitive contexts, it's essential to utilize a cryptographically secure pseudo-random number generator. As a general guideline, a value should be deemed "security-sensitive" if its predictability would empower an attacker to perform actions that would otherwise be beyond their reach. For instance, if an attacker could predict a newly generated user's random password, they would gain unauthorized access to that user's account. For Ruby, ExampleThe following examples show different ways of generating a password. The first example uses defgenerate_password()chars=('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a + ['!','@','#','$','%']# BAD: rand is not cryptographically securepassword=(1..10).collect{chars[rand(chars.size)]}.joinendpassword=generate_passwordIn the second example, the password is generated using require'securerandom'defgenerate_password()chars=('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a + ['!','@','#','$','%']# GOOD: SecureRandom is cryptographically securepassword=SecureRandom.random_bytes(10).each_byte.mapdo |byte|
chars[byte % chars.length]end.joinendpassword=generate_password()References
ruby/ql/src/queries/security/cwe-079/ReflectedXSS.qhelpReflected server-side cross-site scriptingDirectly writing user input (for example, an HTTP request parameter) to a webpage, without properly sanitizing the input first, allows for a cross-site scripting vulnerability. RecommendationTo guard against cross-site scripting, escape user input before writing it to the page. Some frameworks, such as Rails, perform this escaping implicitly and by default. Take care when using methods such as ExampleThe following example is safe because the However, the following example is unsafe because user-controlled input is emitted without escaping, since it is marked as References
ruby/ql/src/queries/security/cwe-079/StoredXSS.qhelpStored cross-site scriptingDirectly writing an uncontrolled stored value (for example, a database field) to a webpage, without properly sanitizing the value first, allows for a cross-site scripting vulnerability. This kind of vulnerability is also called stored cross-site scripting, to distinguish it from other types of cross-site scripting. RecommendationTo guard against stored cross-site scripting, consider escaping before using uncontrolled stored values to create HTML content. Some frameworks, such as Rails, perform this escaping implicitly and by default. Take care when using methods such as ExampleThe following example is safe because the However, the following example may be unsafe because In the next example, content from a file on disk is inserted literally into HTML content. This approach is sometimes used to load script content, such as extensions for a web application, from files on disk. Care should taken in these cases to ensure both that the loaded files are trusted, and that the file cannot be modified by untrusted users. References
ruby/ql/src/queries/security/cwe-079/UnsafeHtmlConstruction.qhelpUnsafe HTML constructed from library inputWhen a library function dynamically constructs HTML in a potentially unsafe way, then it's important to document to clients of the library that the function should only be used with trusted inputs. If the function is not documented as being potentially unsafe, then a client may inadvertently use inputs containing unsafe HTML fragments, and thereby leave the client vulnerable to cross-site scripting attacks. RecommendationDocument all library functions that can lead to cross-site scripting attacks, and guard against unsafe inputs where dynamic HTML construction is not intended. ExampleThe following example has a library function that renders a boldface name by creating a string containing a classUsersController < ActionController::Base# BAD - create a user description, where the name is not escapeddefcreate_user_description(name)"<b>#{name}</b>".html_safeendendThis library function, however, does not escape unsafe HTML, and a client that calls the function with user-supplied input may be vulnerable to cross-site scripting attacks. The library could either document that this function should not be used with unsafe inputs, or escape the input before embedding it in the HTML fragment. classUsersController < ActionController::Base# Good - create a user description, where the name is escapeddefcreate_user_description(name)"<b>#{ERB::Util.html_escape(name)}</b>".html_safeendendReferences
ruby/ql/src/queries/variables/DeadStoreOfLocal.qhelpUseless assignment to local variableA value is assigned to a local variable, but either that variable is never read later on, or its value is always overwritten before being read. This means that the original assignment has no effect, and could indicate a logic error or incomplete code. RecommendationEnsure that you check the control and data flow in the method carefully. If a value is really not needed, consider omitting the assignment. Be careful, though: if the right-hand side has a side-effect (like performing a method call), it is important to keep this to preserve the overall behavior. ExampleIn the following example, the return value of the call to deff(x)result=send(x)waitForResponsereturngetResponseendAssuming that deff(x)result=send(x)# check for errorif(result == -1)raise"Unable to send, check network."endwaitForResponsereturngetResponseendReferences
|
We have some files that need to be synchronized, but apparently are no longer. This makes CI fail and will need to be fixed before we can merge: |
geoffw0
commented
Aug 26, 2026
Let us know if it isn't clear how to fix this (most likely just overwriting the copies with your modified files). |
miachillgood
commented
Sep 1, 2026
Updated the Python synchronized copy in ef1b821. The Java, JavaScript, and Python files now contain the same HTTPS reference. |
Uh oh!
There was an error while loading. Please reload this page.



Update 98 Wikipedia and Wikibooks references in non-Python query-help files from HTTP to HTTPS.
This is a scheme-only change: paths, fragments, and link text remain unchanged. The Python query-help subset remains outside this PR except for the Python copy of
FLinesOfDuplicatedCodeCommon.inc.qhelp, which must match the synchronized Java and JavaScript copies.Validation:
git diff --checkFLinesOfDuplicatedCodeCommon.inc.qhelpfiles are synchronizedPart of #5163.